Skip to main content

Prerequisites

  • An API key. The calldata endpoints need nothing else.
  • An account that can send calls — an ERC-4337 smart account for batching, or an EOA.
  • viem, or any client that can send {to, data, value}.
Amounts are raw token units throughout. Convert with parseUnits(value, decimals) and never send a decimal string.

Recipe 1: Deposit into the best stable market on a chain

Pick the instrument

Filtering on tier, maxCv and minHistoryDays before sorting on APY keeps a two-week incentive programme from outranking a market that has paid steadily for a year.

Build the bundle

Check what it assumes, then send it

simulation.assumedBalances is true on essentially every bundle: the simulator overrode balances to prove the calls work. That check above is the part it did not do for you.

Recipe 2: Withdraw, in full or in part

amount on a withdrawal is denominated in the underlying, not in yield-token shares — balanceRaw from GET /positions, not shareBalanceRaw. Use max to exit fully; it is the only way to catch interest accruing between the quote block and inclusion.
max cannot be combined with tokenOut. A full exit’s proceeds are only known once the withdrawal runs, and an exact-output swap needs the number up front. Ask for an exact underlying amount when you want the output swapped.

Recipe 3: Deposit a token the market does not take

Pass tokenIn and the builder puts a swap leg in front of the deposit:
Swap-bearing bundles are the only ones that carry expiresAt, minOut and leftovers. Check the expiry before signing rather than after a revert, and expect the leftovers dust to stay in the account — it is bounded, not lost.

Recipe 4: Rebalance from one instrument to another

Two bundles, same chain, in order. Withdraw first, then size the deposit to what actually arrived:
Do not build the second bundle before the first one lands. It would be simulated at a block where the proceeds do not exist, and sized to an estimate rather than the balance.

Recipe 5: Move USDC to another chain

Then poll Circle’s Iris API for the attestation, keyed by the source transaction hash and the source domain (burn.sourceDomain). A 404 means the burn is not indexed yet, not that it failed — keep polling. Once the USDC is minted on the destination chain, build the deposit there at that point:
A smart account can redeem and deposit in one operation, so a failing deposit reverts the redemption and leaves the CCTP nonce unused — the destination side can simply be rebuilt. See the execution model.

Handling refusals

The calldata endpoints fail closed. A non-200 is the API declining to hand you something unsafe, and the message says which:

Common pitfalls

  • Sending decimal amounts. "1000.00" is not a raw unit and will be rejected.
  • Treating a 400 as transient and retrying it unchanged.
  • Passing yield-token shares as a withdrawal amount — it takes the underlying.
  • Reusing a swap-bearing bundle past expiresAt, or any bundle long after quoteBlock.
  • Sizing a deposit to the account’s full USDC balance on a smart account, leaving nothing for the paymaster’s maximum charge.
  • Building a destination-chain bundle before the bridged funds have been minted.
  • Assuming requires was checked for you — assumedBalances says it was not.

Next steps

Calldata API

Full request and response shapes

Loops API

Levered positions in one batch

Execution Model

Gas, accounts and CCTP rules

Portfolio API

Score an allocation before you move it