base-usdc-aave-v3-lending, discovered by filtering GET /v1/yields for network=base, inputToken=USDC, and types=lending. Swap in whatever id your own discovery step returns; see Discover yields.
Prerequisites
- A yield.xyz API key, sent as
x-api-keyon every request. - A yield enabled for your project with
status.enter(and, for the exit half of this guide,status.exit)true. See Discover yields. - A signer for the target chain (an EOA, smart account, MPC, or custodial signer). This guide uses a generic
signAndBroadcastplaceholder; see Transaction signing for chain-specific signing code, including EVM.
We construct. You sign. Every action returns unsigned transactions; yield.xyz never holds keys and never signs on your behalf. Inspect
unsignedTransaction before signing it, and never modify its values.Find and inspect the yield
Fetch the full metadata for the yield you discovered, and read its enter schema before building a request:cURL
Response (excerpt)
status.enter must be true before you offer this yield for entry. mechanics.arguments.enter.fields is the schema you build the request from in the next step, not a fixed set of fields you can assume across yields.
Build the enter arguments from the schema
Never hardcode{ amount } as the request body. Build it from mechanics.arguments.enter.fields, so the same code works for a yield that also requires a validatorAddress, an inputToken, or another field:
base-usdc-aave-v3-lending, only amount is required; receiverAddress and executionMode are optional and omitted here.
Enter a position
1
Request the enter action
Call Entering USDC lending on Aave needs an ERC-20 approval before the supply call, so this action returns two transactions. The
POST /v1/actions/enter with the yieldId, the user’s address, and the arguments you built. It returns 201 Created with an action and its ordered transactions.Response (excerpt)
unsignedTransaction values above are placeholders for the serialized payloads the API returns; pass each one to your signer exactly as received.2
Branch on executionPattern
action.executionPattern decides how you drive transactions, sorted by stepIndex:Actions currently come back as
synchronous or batch; handle asynchronous too so your code keeps working if a yield starts returning it. base-usdc-aave-v3-lending returns synchronous here: the supply transaction depends on the approval being confirmed first. Skip any transaction whose status is already terminal (CONFIRMED, FAILED, or SKIPPED, for example an approval skipped because an existing allowance already covers the amount) instead of signing it again.3
Sign, choose a submit path, and poll
For each transaction: sign Poll
unsignedTransaction, then choose one of the two submit endpoints, never both for the same transaction.POST /v1/transactions/{transactionId}/submit, withsignedTransaction: hand yield.xyz the signed transaction and it broadcasts. Useful when your backend has no RPC access of its own.PUT /v1/transactions/{transactionId}/submit-hash, withhash: broadcast the signed transaction through your own infrastructure, then report the resulting hash.
GET /v1/transactions/{id} (or GET /v1/actions/{id} for the whole action) every few seconds with a bounded overall timeout until the status is terminal. Polling always works; webhooks can push status changes too, but keep polling as the fallback. Submitting a different hash for a transaction that is already terminal returns 412 Precondition Failed; treat that as already settled rather than retrying.Verify the balance
Once the last transaction confirms, read the resulting position:cURL
Response (excerpt)
active balance with no pendingActions means the position is fully entered with nothing to follow up on. See Balances and positions for every balance type and field.
Exit a position
Exit follows the same request, sign, submit, poll loop as enter, throughPOST /v1/actions/exit and its own argument schema (mechanics.arguments.exit, not .enter). For base-usdc-aave-v3-lending, that schema offers amount, useMaxAmount, and receiverAddress:
cURL
useMaxAmount: true redeems the full position instead of a specific amount, when the schema offers it, as this one does. The response is another ActionDto with its own executionPattern and transactions: run it through the same branch, sign, submit, and poll steps as enter. Aave has no cooldown, so exiting this yield settles directly, with no intermediate balance state to wait out.
Complete a pending action (manage)
When an exit (or an entered position generally) leaves apendingActions entry on a balance, for example that CLAIM_UNSTAKED after a cooldown, or a routine CLAIM_REWARDS, execute it with POST /v1/actions/manage. Pass the pending action’s own type as action and its passthrough unchanged (copied from the balances response, never constructed):
cURL
ActionDto with transactions[]: run the same branch, sign, submit, and poll loop as enter and exit. See Balances and positions for where pendingActions come from.
Errors that block the flow
Next steps
Transaction signing
Chain-specific signing code for EVM, Solana, Cosmos, and Tron.
Tracking balances
Build portfolio and position views across multiple yields.
Monitoring and alerting
Keep action and position state current after submission.
Lending
Apply this loop to a lending market, from supply to withdrawal.

