> ## Documentation Index
> Fetch the complete documentation index at: https://docs.portalhq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Lend and borrow with Yield.xyz

> Learn how to supply collateral, borrow, repay and withdraw on lending protocols using the Enclave MPC API and the Yield.xyz integration.

Portal's Enclave MPC API lets your users lend and borrow on Aave V3, Morpho Blue, SparkLend and Lista through the Yield.xyz integration. This guide covers discovering lending markets, building supply / borrow / repay / withdraw actions, signing and submitting the resulting transactions, and tracking positions.

## Overview

The lend & borrow functionality allows you to:

* **Discover** the lending integrations (protocols) and the markets your project has enabled, with live rates, LTVs, liquidation thresholds and liquidity
* **Supply** tokens as collateral and **borrow** against them
* **Repay** debt and **withdraw** collateral, or toggle a supplied asset as collateral
* **Track** positions (supply and debt balances, health factor, LTV and available borrow) and liquidation history

To summarize: a user supplies collateral, can borrow up to the market's `maxLtv` of its value, pays a floating borrow rate with no term, and is liquidated (partially, with a penalty) only if the position's `healthFactor` drops below `1`. The [integration page](/integrations/Yield/yield-xyz-borrow#how-lending-and-borrowing-works) explains the mechanics and why you might offer it.

All endpoints live under `https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow` and return `{ "data": ... }`. Chain ids are [CAIP-2](/resources/chain-id-formatting) everywhere (`eip155:8453` for Base).

## Prerequisites

Before using lend & borrow operations, ensure you have:

* A properly initialized Portal client (see [Create a client](./create-a-client))
* An active wallet with the required token(s) **and gas** on the target network (see [Create a wallet](./create-a-wallet))
* Yield.xyz integration enabled in your Portal Dashboard, with the lending markets you want to offer enabled in the Yield.xyz dashboard (see [Yield.xyz Borrow](/integrations/Yield/yield-xyz-borrow))

<Warning>
  Lending integrations are live on **mainnets only**: there are no Sepolia, Base Sepolia or Amoy markets, so `POST /api/v3/clients/me/fund` cannot be used here. Test with small amounts on an inexpensive chain such as Base. The examples below use Aave V3 USDC on Base.
</Warning>

## Discovering Integrations

Use the `GET /api/v3/clients/me/integrations/yield-xyz-borrow/integrations` endpoint to list the lending protocols, the networks each supports and the actions each exposes (including the argument schema per action).

For complete API documentation, see the [API reference](/api-reference/yieldxyz-borrow/list-integrations).

```bash theme={null}
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/integrations' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
```

Integration ids look like `aave-borrow`, `morpho-blue-borrow`, `sparklend-borrow` and `lista-borrow`; use the ids the endpoint returns rather than a fixed list. Use `GET .../integrations/{integrationId}` for one integration.

## Discovering Markets

Use the `GET /api/v3/clients/me/integrations/yield-xyz-borrow/markets` endpoint to list lending markets. By default only markets you enabled in the Yield.xyz dashboard are returned (`scope=enabled`); pass `scope=all` to browse everything Yield.xyz supports.

For complete API documentation, see the [API reference](/api-reference/yieldxyz-borrow/list-lending-markets).

```bash theme={null}
# Enabled Aave V3 markets on Base
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/markets?integrationId=aave-borrow&network=eip155:8453' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'

# Browse every market Yield.xyz supports
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/markets?scope=all&limit=50' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
```

Each market carries the fields you need to render a lending UI: `loanToken`, `collateralTokens[]` (with `maxLtv`, `liquidationThreshold`, `liquidationPenalty`, `supplyRate`), `borrowRate`, `availableLiquidity`, `utilizationRate`, `isBorrowEnabled`, `minLoan` and the fee settings. Treat market ids as opaque values returned by `GET /markets` (for example `aave-borrow-base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913` for USDC on Base); they embed the Yield.xyz network slug, not the CAIP-2 chain id, so do not build them yourself.

<Note>
  If `scope=enabled` returns an empty list, no markets are enabled for your project yet. Enable them in the Yield.xyz dashboard, the same way you enable yield opportunities. Enabling only affects what `GET /markets` lists by default; actions can be built for any market id.
</Note>

## Supplying Collateral

To supply, use the `POST /api/v3/clients/me/integrations/yield-xyz-borrow/actions` endpoint to create the action and get the transaction(s) to sign. You'll then sign each with the Enclave MPC API and report the hash back.

For complete API documentation, see the [API reference](/api-reference/yieldxyz-borrow/execute-a-borrow-action).

### Step 1: Create the Supply Action

```bash theme={null}
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/actions \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "integrationId": "aave-borrow",
  "action": "supply",
  "address": "0xYourAddress",
  "args": {
    "marketId": "aave-borrow-base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
    "tokenAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "amount": "5"
  }
}'
```

<Note>
  Pool-based protocols (Aave) require `tokenAddress` on `supply` and `withdraw`: the market's `loanToken.address` to supply the loan asset, or one of `collateralTokens[].token.address` to supply a different collateral. Isolated-market protocols (Morpho Blue) infer it from `marketId`. `GET .../integrations/{integrationId}` returns the exact JSON schema for every action's `args`.
</Note>

```json theme={null}
// Example response (trimmed)
{
  "data": {
    "id": "act_...",
    "integrationId": "aave-borrow",
    "action": "supply",
    "address": "0xYourAddress",
    "status": "CREATED",
    "hasNextStep": false,
    "currentStep": 1,
    "totalSteps": 1,
    "transactions": [
      {
        "id": "73729c4d-...",
        "network": "eip155:8453",
        "type": "APPROVAL",
        "status": "CREATED",
        "address": "0xYourAddress",
        "signingFormat": "EVM_TRANSACTION",
        "signablePayload": "{\"from\":\"0xYourAddress\",\"gasLimit\":\"56240\",\"to\":\"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\"data\":\"0x095ea7b3...\"}"
      },
      {
        "id": "5925b16e-...",
        "network": "eip155:8453",
        "type": "SUPPLY",
        "status": "CREATED",
        "address": "0xYourAddress",
        "signingFormat": "EVM_TRANSACTION",
        "signablePayload": "{\"from\":\"0xYourAddress\",\"gasLimit\":\"420000\",\"to\":\"0xA238Dd80C259a72e81d7e4664a9801593F98d1c5\",\"data\":\"0x617ba037...\"}"
      }
    ],
    "metadata": {
      "currentHealthFactor": null,
      "predictedHealthFactor": null,
      "currentLtv": "0",
      "predictedLtv": "0",
      "predictedTotalSupplyUsd": "5.00",
      "predictedTotalDebtUsd": "0"
    }
  }
}
```

<Note>
  Take note of `data.id` (the action id), each transaction's `id`, and `hasNextStep`. A step can contain several transactions (here the ERC-20 approval and the supply), which you sign and submit **in order**, waiting for each to confirm. Some actions add further steps (`hasNextStep: true`), fetched with the step endpoint below. Yield.xyz builds the transactions even if the wallet does not hold the tokens yet; the balance check happens on-chain.
</Note>

### Step 2: Sign and Broadcast with the Enclave MPC API

`signablePayload` for `EVM_TRANSACTION` is a JSON string of the unsigned transaction. Parse it and pass the fields to the Enclave MPC API `eth_sendTransaction` method, which signs **and** broadcasts, returning the transaction hash.

```bash theme={null}
curl --request POST \
  --url https://mpc-client.portalhq.io/v1/sign \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "share": "[share]",
  "method": "eth_sendTransaction",
  "params": { "from": "0xYourAddress", "to": "0x8335...", "data": "0x095ea7b3...", "value": "0x0" },
  "rpcUrl": "https://api.portalhq.io/rpc/v1/eip155/8453",
  "chainId": "eip155:8453"
}'
```

<Tip>
  Remove the gas parameters from the parsed payload if you want Portal to estimate gas for you. If you prefer to broadcast yourself, use `eth_signTransaction` instead and send the signed raw transaction as `signedPayload` in the next step, and Yield.xyz will broadcast it.
</Tip>

### Step 3: Submit the Transaction Hash

Report the hash to Yield.xyz with `POST /api/v3/clients/me/integrations/yield-xyz-borrow/transactions/{transactionId}/submit` so it can track confirmation and unlock the next step.

For complete API documentation, see the [API reference](/api-reference/yieldxyz-borrow/submit-signed-transaction).

```bash theme={null}
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/transactions/[transactionId]/submit \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "transactionHash": "0x..."
}'
```

The response includes the transaction `status` and an explorer `link`.

### Step 4: Fetch the Next Step

When the action has `hasNextStep: true`, wait for the submitted transaction to confirm, then call `POST /api/v3/clients/me/integrations/yield-xyz-borrow/actions/{id}/step` to get the next transaction(s) and repeat steps 2–3. You can check progress at any time with `GET .../actions/{id}`.

For complete API documentation, see the [API reference](/api-reference/yieldxyz-borrow/get-next-step-transactions).

```bash theme={null}
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/actions/[actionId]/step \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
```

The action is complete when `status` is `SUCCESS` and `hasNextStep` is `false`.

## Borrowing

Borrowing uses the same action flow with `"action": "borrow"`. Supplied assets on Aave are collateral by default; on other integrations, or if you disabled it, run an `enableCollateral` action first. You can also combine both in one flow with `supplyAndBorrow`.

```bash theme={null}
# Borrow 2 USDC against your collateral
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/actions \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "integrationId": "aave-borrow",
  "action": "borrow",
  "address": "0xYourAddress",
  "args": {
    "marketId": "aave-borrow-base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
    "amount": "2"
  }
}'

# Or supply collateral and borrow in one action
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/actions \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "integrationId": "aave-borrow",
  "action": "supplyAndBorrow",
  "address": "0xYourAddress",
  "args": {
    "marketId": "aave-borrow-base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
    "collateralTokenAddress": "0x4200000000000000000000000000000000000006",
    "collateralAmount": "0.01",
    "borrowAmount": "10"
  }
}'
```

<Note>
  Every action response carries `metadata.predictedHealthFactor` and `metadata.predictedLtv`. Show these to the user before they sign: a health factor at or below `1` means the position can be liquidated. The exact `args` each action accepts (`amount`, `amountRaw`, `repayAll`, `tokenAddress`, `targetLtv` and so on) are described per integration in `GET .../integrations/{integrationId}`.
</Note>

## Checking Positions

Retrieve a user's position on an integration + network with the `GET /api/v3/clients/me/integrations/yield-xyz-borrow/positions` endpoint.

For complete API documentation, see the [API reference](/api-reference/yieldxyz-borrow/get-positions).

```bash theme={null}
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/positions?integrationId=aave-borrow&network=eip155:8453&address=0xYourAddress' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
```

```json theme={null}
// Example response (trimmed)
{
  "data": {
    "address": "0xYourAddress",
    "integrationId": "aave-borrow",
    "network": "eip155:8453",
    "totalSuppliedUsd": "5.00",
    "totalCollateralUsd": "5.00",
    "totalBorrowedUsd": "2.00",
    "netWorthUsd": "3.00",
    "healthFactor": "1.93",
    "currentLtv": "0.40",
    "availableToBorrowUsd": "1.85",
    "netApy": "0.021",
    "supplyBalances": [
      {
        "marketId": "aave-borrow-base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
        "tokenSymbol": "USDC",
        "balance": "5.000123",
        "balanceUsd": "5.00",
        "apy": "0.038",
        "isCollateral": true,
        "pendingActions": [
          { "type": "withdraw", "label": "Withdraw", "args": { "marketId": "aave-borrow-base-0x8335..." } }
        ]
      }
    ],
    "debtBalances": [
      {
        "marketId": "aave-borrow-base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
        "tokenSymbol": "USDC",
        "balance": "2.000041",
        "balanceUsd": "2.00",
        "apy": "0.051",
        "pendingActions": [
          { "type": "repay", "label": "Repay", "args": { "marketId": "aave-borrow-base-0x8335..." } }
        ]
      }
    ]
  }
}
```

Each balance lists `pendingActions`, the actions currently available for that balance, with pre-filled `args` you can pass straight to `POST .../actions`.

## Repaying and Withdrawing

Repay debt with `"action": "repay"` (pass `"repayAll": true` to clear the position, which avoids dust from accrued interest), then withdraw collateral with `"action": "withdraw"`. Both follow the same sign → submit → step flow.

```bash theme={null}
# Repay everything
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/actions \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "integrationId": "aave-borrow",
  "action": "repay",
  "address": "0xYourAddress",
  "args": {
    "marketId": "aave-borrow-base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
    "repayAll": true
  }
}'

# Withdraw collateral
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/actions \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "integrationId": "aave-borrow",
  "action": "withdraw",
  "address": "0xYourAddress",
  "args": {
    "marketId": "aave-borrow-base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
    "tokenAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "amount": "5"
  }
}'
```

## Action History and Liquidations

List a user's past actions with `GET /api/v3/clients/me/integrations/yield-xyz-borrow/actions?address=0xYourAddress` (filter by `integrationId`, `action` or `status`), and their liquidation history with `GET .../positions/liquidations?integrationId=morpho-blue-borrow&network=eip155:1&address=0xYourAddress` (Morpho Blue integrations only).

For complete API documentation, see the [actions](/api-reference/yieldxyz-borrow/list-actions) and [liquidations](/api-reference/yieldxyz-borrow/get-liquidation-history) references.

## Transaction Processing

Lend & borrow actions can require multiple transactions across multiple steps. Process them sequentially: sign each with the Enclave MPC API, submit its hash, wait for on-chain confirmation (e.g. `eth_getTransactionReceipt`), then request the next step.

```bash theme={null}
# 1. Create the action and read data.transactions (and data.hasNextStep)
# 2. For each transaction that is not yet CONFIRMED/SKIPPED/FAILED (fresh ones are CREATED), in array order:
#    a. Parse signablePayload (JSON string) into { from, to, data, value }
#    b. Sign + broadcast with the Enclave MPC API
curl --request POST \
  --url https://mpc-client.portalhq.io/v1/sign \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "share": "[share]",
  "method": "eth_sendTransaction",
  "params": { "from": "0xYourAddress", "to": "0x...", "data": "0x...", "value": "0x0" },
  "rpcUrl": "https://api.portalhq.io/rpc/v1/eip155/8453",
  "chainId": "eip155:8453"
}'

#    c. Submit the hash
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz-borrow/transactions/[transactionId]/submit \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{ "transactionHash": "0x..." }'

#    d. Wait for confirmation
curl --request POST \
  --url https://api.portalhq.io/rpc/v1/eip155/8453 \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{ "id": 1, "jsonrpc": "2.0", "method": "eth_getTransactionReceipt", "params": ["0xTransactionHash"] }'

# 3. If hasNextStep is true, POST .../actions/[actionId]/step and repeat from 2
```

<Tip>
  For account abstraction enabled Portal clients, `eth_sendTransaction` returns a *user operation hash*. Resolve it with `GET /api/v3/clients/me/chains/{chain}/transactions/{userOpHash}` and submit `evmUserOperation.receipt.hash` (the on-chain **transaction hash**) to Yield.xyz, never the user operation hash. Use the smart-account address (the client's `eip155` address) as `address` in every Borrow call.
</Tip>

## Handling Errors

Yield.xyz Borrow errors are returned as Portal errors:

* `400`: invalid request (the message names the field), an unsupported chain id, a request Yield.xyz rejected (its message is passed through), or a Yield.xyz API key that is missing or was rejected
* `404`: unknown market, integration, action or transaction id
* `429`: Yield.xyz rate limit hit; back off and retry
* `503`: Yield.xyz is unreachable or failed upstream
* `500` with `id: INTEGRATION_RESPONSE_SCHEMA_DRIFT`: Yield.xyz changed a response shape and Portal did not forward it. Treat it as a temporary outage of that feature; see [Error codes](/resources/error-codes)

Response enumerations (action and transaction statuses, action types) may gain values over time; treat values you do not recognize as opaque rather than failing.

## Best Practices

1. **Show the predicted health factor and LTV** from `metadata` before the user signs a borrow or withdraw
2. **Process transactions sequentially** and wait for confirmation before requesting the next step
3. **Use `repayAll`** when closing a position so accrued interest does not leave dust
4. **Enable only the markets you support** in the Yield.xyz dashboard so `GET /markets` returns exactly what your UI offers
5. **Handle `INTEGRATION_RESPONSE_SCHEMA_DRIFT`** as a feature outage rather than a user error
6. **Keep gas on the wallet**: every step is an on-chain transaction

## Supported Networks

Lending integrations run on mainnets only; the exact list per protocol is returned by `GET /api/v3/clients/me/integrations/yield-xyz-borrow/integrations` (`networks[]`, as CAIP-2). Aave V3 covers the major EVM chains (Ethereum `eip155:1`, Base `eip155:8453`, Arbitrum `eip155:42161`, Optimism `eip155:10`, Polygon `eip155:137`, Avalanche `eip155:43114`, and more); Morpho Blue covers Ethereum, Base and other EVM chains; SparkLend is Ethereum-only; Lista runs on BNB Chain (`eip155:56`) and Ethereum.

## Next Steps

* Set up the integration: [Yield.xyz Borrow](/integrations/Yield/yield-xyz-borrow)
* Learn about [signing Ethereum transactions](./sign-ethereum-transactions)
* Check out the [Yield.xyz Borrow API reference](/api-reference/yieldxyz-borrow/get-positions)
