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

# Discover yields

> Build the list and detail layer of a Yield API integration: confirm what's enabled, filter, paginate, and read the fields before offering a yield.

Build the layer of your app that lists yields and shows one in detail: confirm what your project has enabled, filter and paginate that list, then fetch and read the fields a user interface or backend needs before offering a position.

## Prerequisites

* A yield.xyz API key, sent as `x-api-key` on every request. See [Projects & API keys](/documentation/get-started/projects-api-keys).
* At least one yield enabled for your project. `GET /v1/yields` is [project-scoped](/documentation/earn/core-concepts/discover#availability-is-project-scoped) and returns nothing for a project with no yields enabled.

<Steps>
  <Step title="Confirm what's enabled">
    Call `GET /v1/yields` with no filters and a small `limit` to check what your project has access to before building any UI around it.

    <CodeGroup>
      ```bash cURL theme={null}
      curl --request GET \
        --url 'https://api.yield.xyz/v1/yields?limit=1' \
        --header "x-api-key: $YIELD_API_KEY"
      ```

      ```typescript TypeScript theme={null}
      const res = await fetch('https://api.yield.xyz/v1/yields?limit=1', {
        headers: { 'x-api-key': process.env.YIELD_API_KEY! },
      });
      const { items, total } = await res.json();
      ```
    </CodeGroup>

    `total` in the response tells you how many yields your project has enabled overall, regardless of `limit`. A `total` of `0` means the project has nothing enabled yet: see Step 3.
  </Step>

  <Step title="Filter and paginate">
    Narrow the list with query parameters, combined as needed. For an integration that only offers stablecoin lending on Base, for example, filter by `network`, `inputToken`, and `types`:

    <CodeGroup>
      ```bash cURL theme={null}
      curl --request GET \
        --url 'https://api.yield.xyz/v1/yields?network=base&inputToken=USDC&types=lending&limit=20&offset=0' \
        --header "x-api-key: $YIELD_API_KEY"
      ```

      ```typescript TypeScript theme={null}
      const params = new URLSearchParams({
        network: 'base',
        inputToken: 'USDC',
        types: 'lending',
        limit: '20',
        offset: '0',
      });
      const res = await fetch(`https://api.yield.xyz/v1/yields?${params}`, {
        headers: { 'x-api-key': process.env.YIELD_API_KEY! },
      });
      const { items, total, offset, limit } = await res.json();
      ```
    </CodeGroup>

    ```json Response (excerpt) theme={null}
    {
      "items": [
        { "id": "base-usdc-aave-v3-lending", "network": "base", "providerId": "aave" }
      ],
      "total": 1,
      "offset": 0,
      "limit": 20
    }
    ```

    `base-usdc-aave-v3-lending` is a discovered result here, not a fixed value: pick `items[0].id`, or let the user pick from the list, rather than hardcoding an ID in your app. `limit` defaults to 20 and caps at 100 per request; page through a larger result set with `offset`. See [Discover](/documentation/earn/core-concepts/discover#filter-your-yields) for the full filter list, including `provider`, `search`, `prime`, `hasCooldownPeriod`, and `sort`.
  </Step>

  <Step title="Handle an empty result">
    An empty `items` array with `total: 0` means either the filters matched nothing, or the project has no yields enabled at all. Distinguish the two by re-running the same request with every filter removed:

    * If the unfiltered call also returns `total: 0`, no yields are enabled for this project yet. Enable some from the [dashboard](https://dashboard.yield.xyz) or through [Programmatic access](/documentation/advanced-setup/programmatic-access), then retry.
    * If the unfiltered call returns results, the filters were too narrow. Relax them (drop `inputToken` or `type` first) rather than showing a dead end.

    Design the empty state around this distinction instead of showing a generic "no results" message for both cases.
  </Step>

  <Step title="Fetch one yield">
    Once a user picks a yield (or your backend needs full detail on one), fetch it by `id` for the complete metadata object:

    <CodeGroup>
      ```bash cURL theme={null}
      curl --request GET \
        --url https://api.yield.xyz/v1/yields/base-usdc-aave-v3-lending \
        --header "x-api-key: $YIELD_API_KEY"
      ```

      ```typescript TypeScript theme={null}
      const res = await fetch(
        'https://api.yield.xyz/v1/yields/base-usdc-aave-v3-lending',
        { headers: { 'x-api-key': process.env.YIELD_API_KEY! } },
      );
      const yield_ = await res.json();
      ```
    </CodeGroup>

    A yield not enabled for your project, including one from a stale ID your app cached earlier, returns `400 Bad Request` here. Re-run discovery instead of assuming a previously seen ID stays valid.
  </Step>

  <Step title="Read the fields before offering it">
    Before showing an enter or exit button, read the fields that tell you whether the action is currently possible and what it needs:

    ```json Response (excerpt) theme={null}
    {
      "status": { "enter": true, "exit": true },
      "rewardRate": { "total": 0.0431, "rateType": "APY" },
      "inputTokens": [{ "symbol": "USDC", "decimals": 6 }],
      "outputToken": { "symbol": "aBasUSDC", "decimals": 6 },
      "mechanics": {
        "requiresValidatorSelection": false,
        "entryLimits": { "minimum": "0", "maximum": null, "subsequentMinimum": null },
        "requirements": { "kycRequired": false },
        "arguments": {
          "enter": { "fields": [{ "name": "amount", "required": true }] }
        }
      },
      "metadata": { "underMaintenance": false }
    }
    ```

    | Field | Tells you | Use it to |
    | - | - | - |
    | `status.enter` / `status.exit` | Whether entering or exiting is open right now | Enable or disable the corresponding button |
    | `metadata.underMaintenance` | Protocol-side maintenance flag | Hide the yield, or show a maintenance notice, even if `status.enter` is still `true` |
    | `rewardRate` | Effective yield, broken down by source and token | Display the rate you show the user |
    | `inputTokens` / `outputToken` | Accepted deposit tokens, and the token received back (if any) | Populate token pickers and show what the user ends up holding |
    | `mechanics.arguments.enter.fields` | The schema-driven list of inputs the enter action needs | Build the enter form; see [Enter and exit flows](/guides/earn/enter-exit-flows#build-the-enter-arguments-from-the-schema) |
    | `mechanics.entryLimits` | Minimum, maximum, and subsequent-minimum entry amount (any can be `null`) | Validate an amount client-side before requesting an action |
    | `mechanics.cooldownPeriod` / `mechanics.warmupPeriod` | Time before an exit settles, or before rewards start accruing | Set expectations in the UI; omitted entirely on yields with no such period |
    | `mechanics.requiresValidatorSelection` | Whether entering requires picking a validator | Route to a validator picker; see [Staking](/documentation/earn/staking/index) |
    | `mechanics.requirements.kycRequired` | Whether off-chain KYC gates this yield | Route to KYC first; see [KYC](/documentation/earn/rwas/kyc) |

    `entryLimits`, `cooldownPeriod`, and `warmupPeriod` are each optional and can be entirely absent, not just `null`: `base-usdc-aave-v3-lending` above has no cooldown, since Aave V3 lending has no unbonding step. Check for the field before reading its sub-values. See [Yield metadata](/documentation/earn/core-concepts/yield-metadata) for the full object reference.
  </Step>

  <Step title="Optional: build an asset-first picker">
    To let a user start from a network or a token instead of a yield list, query the two supporting catalogs. Both are project-scoped the same way as `GET /v1/yields`.

    <CodeGroup>
      ```bash Networks theme={null}
      curl --request GET \
        --url 'https://api.yield.xyz/v1/networks' \
        --header "x-api-key: $YIELD_API_KEY"
      ```

      ```bash Tokens theme={null}
      curl --request GET \
        --url 'https://api.yield.xyz/v1/tokens?networks=base&symbol=USDC' \
        --header "x-api-key: $YIELD_API_KEY"
      ```
    </CodeGroup>

    Use the returned networks or tokens to pre-filter `GET /v1/yields` (Step 2) once the user picks one, rather than fetching every yield and filtering client-side.
  </Step>
</Steps>

## Next steps

<Columns cols={2}>
  <Card title="Enter and exit flows" icon="arrow-right-arrow-left" href="/guides/earn/enter-exit-flows">
    Turn a discovered yield into a signed, submitted, and tracked position.
  </Card>

  <Card title="Validator selection" icon="user-check" href="/guides/earn/staking/validator-selection">
    Choose a validator when a staking yield requires one.
  </Card>

  <Card title="Check RWA eligibility" icon="badge-check" href="/guides/earn/rwas/check-eligibility">
    Confirm KYC status before entering a yield that requires it.
  </Card>

  <Card title="Yield metadata" icon="tags" href="/documentation/earn/core-concepts/yield-metadata">
    Full reference for every field on the yield object.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.