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

# Protocols

> List DeFi protocols available on a specific chain

Retrieve a paginated list of DeFi protocols available on a specific blockchain network. Use the `chainKey` from the [Chains](/api/endpoints/chains) endpoint to specify which chain to query.

<Info>
  **Cost:** Free (0 credits)
</Info>

<Note>
  **Interactive Playground:** Test this endpoint in the [API Playground](/api-reference/protocols). Get your API key at [data.octav.fi](https://data.octav.fi/)
</Note>

***

## Endpoint

<CodeGroup>
  ```bash Request theme={null}
  GET https://api.octav.fi/v1/chains/:chainKey/protocols
  ```

  ```bash Example theme={null}
  curl -X GET "https://api.octav.fi/v1/chains/ethereum/protocols?page=1&limit=20" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```
</CodeGroup>

***

## Parameters

<ParamField path="chainKey" type="string" required>
  The chain identifier (e.g. `ethereum`, `solana`, `arbitrum`). Must match a chain's `key` field from the [Chains](/api/endpoints/chains) endpoint.

  ```
  /v1/chains/ethereum/protocols
  ```
</ParamField>

<ParamField query="page" type="integer" default="1">
  Page number for pagination

  * **Minimum:** 1
</ParamField>

<ParamField query="limit" type="integer" default="20">
  Number of protocols per page

  * **Minimum:** 1
  * **Maximum:** 100
</ParamField>

***

## Response

Returns a paginated list of protocol objects.

### Top-Level Fields

<ResponseField name="data" type="array">
  Array of protocol objects (see fields below)
</ResponseField>

<ResponseField name="pagination" type="object">
  Pagination metadata:

  * `page` — Current page number
  * `limit` — Items per page
  * `hasMore` — Whether more pages are available
</ResponseField>

### Protocol Fields

<ResponseField name="uuid" type="string">
  Unique protocol identifier
</ResponseField>

<ResponseField name="key" type="string">
  Protocol key (e.g. `"aave"`, `"uniswap v3"`)
</ResponseField>

<ResponseField name="name" type="string">
  Display name (e.g. `"Aave"`, `"Uniswap V3"`)
</ResponseField>

<ResponseField name="imgSmall" type="string">
  URL to small protocol icon
</ResponseField>

<ResponseField name="imgLarge" type="string">
  URL to large protocol icon
</ResponseField>

<ResponseField name="isUserProtocol" type="boolean">
  `true` if this is a user-created custom protocol. Custom protocols only appear on page 1 and are listed before system protocols.
</ResponseField>

***

## Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.octav.fi/v1/chains/ethereum/protocols?page=1&limit=20" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const chainKey = 'ethereum';

  const response = await fetch(
    `https://api.octav.fi/v1/chains/${chainKey}/protocols?page=1&limit=20`,
    {
      headers: {
        'Authorization': `Bearer ${apiKey}`
      }
    }
  );

  const { data: protocols, pagination } = await response.json();
  console.log(`Found ${protocols.length} protocols (hasMore: ${pagination.hasMore})`);
  ```

  ```python Python theme={null}
  import requests

  chain_key = 'ethereum'

  response = requests.get(
      f'https://api.octav.fi/v1/chains/{chain_key}/protocols',
      params={'page': 1, 'limit': 20},
      headers={'Authorization': f'Bearer {api_key}'}
  )

  result = response.json()
  protocols = result['data']
  pagination = result['pagination']
  print(f'Found {len(protocols)} protocols (hasMore: {pagination["hasMore"]})')
  ```

  ```typescript TypeScript theme={null}
  interface Protocol {
    uuid: string;
    key: string;
    name: string;
    imgSmall: string;
    imgLarge: string;
    isUserProtocol: boolean;
  }

  interface ProtocolResponse {
    data: Protocol[];
    pagination: {
      page: number;
      limit: number;
      hasMore: boolean;
    };
  }

  const chainKey = 'ethereum';

  const response = await fetch(
    `https://api.octav.fi/v1/chains/${chainKey}/protocols?page=1&limit=20`,
    {
      headers: {
        'Authorization': `Bearer ${apiKey}`
      }
    }
  );

  const { data: protocols, pagination }: ProtocolResponse = await response.json();
  console.log(`Found ${protocols.length} protocols (hasMore: ${pagination.hasMore})`);
  ```
</CodeGroup>

***

## Example Response

```json theme={null}
{
  "data": [
    {
      "uuid": "abc12345-1234-5678-9abc-def012345678",
      "key": "aave",
      "name": "Aave",
      "imgSmall": "https://images.octav.fi/tokens/small/aave_small_icon.png",
      "imgLarge": "https://images.octav.fi/tokens/large/aave_large_icon.png",
      "isUserProtocol": false
    },
    {
      "uuid": "def67890-1234-5678-9abc-def012345678",
      "key": "uniswap v3",
      "name": "Uniswap V3",
      "imgSmall": "https://images.octav.fi/tokens/small/uniswap_small_icon.png",
      "imgLarge": "https://images.octav.fi/tokens/large/uniswap_large_icon.png",
      "isUserProtocol": false
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "hasMore": true
  }
}
```

***

## Pagination

The endpoint uses page-based pagination. Use `page` and `limit` to navigate through results.

<AccordionGroup>
  <Accordion title="How Pagination Works" icon="book-open">
    * **Default behavior:** Returns 20 protocols per page starting from page 1
    * **`hasMore` flag:** Indicates whether additional pages exist
    * **User protocols:** Custom user-created protocols are prepended on page 1 only
    * **Ordering:** System protocols are returned in a consistent order
  </Accordion>

  <Accordion title="Paginating Through All Protocols" icon="forward">
    Fetch all protocols for a chain by iterating until `hasMore` is `false`:

    ```javascript theme={null}
    async function getAllProtocols(chainKey) {
      const allProtocols = [];
      let page = 1;
      let hasMore = true;

      while (hasMore) {
        const response = await fetch(
          `https://api.octav.fi/v1/chains/${chainKey}/protocols?page=${page}&limit=100`,
          { headers: { 'Authorization': `Bearer ${apiKey}` } }
        );

        const result = await response.json();
        allProtocols.push(...result.data);
        hasMore = result.pagination.hasMore;
        page++;
      }

      return allProtocols;
    }

    const protocols = await getAllProtocols('ethereum');
    console.log(`Total protocols on Ethereum: ${protocols.length}`);
    ```
  </Accordion>
</AccordionGroup>

***

## Use Cases

<Tabs>
  <Tab title="Protocol Selector" icon="list">
    Build a protocol selection dropdown for your UI:

    ```javascript theme={null}
    async function loadProtocolOptions(chainKey) {
      const response = await fetch(
        `https://api.octav.fi/v1/chains/${chainKey}/protocols?limit=100`,
        { headers: { 'Authorization': `Bearer ${apiKey}` } }
      );

      const { data: protocols } = await response.json();

      return protocols.map(protocol => ({
        value: protocol.key,
        label: protocol.name,
        icon: protocol.imgSmall,
        isCustom: protocol.isUserProtocol
      }));
    }

    // Populate dropdown when user selects a chain
    const options = await loadProtocolOptions('ethereum');
    ```
  </Tab>

  <Tab title="Multi-Chain Protocols" icon="layer-group">
    Find which protocols are available across chains:

    ```javascript theme={null}
    async function getProtocolsByChains(chainKeys) {
      const results = {};

      for (const chainKey of chainKeys) {
        const response = await fetch(
          `https://api.octav.fi/v1/chains/${chainKey}/protocols?limit=100`,
          { headers: { 'Authorization': `Bearer ${apiKey}` } }
        );

        const { data } = await response.json();
        results[chainKey] = data.map(p => p.key);
      }

      return results;
    }

    const protocols = await getProtocolsByChains(['ethereum', 'arbitrum', 'base']);
    console.log('Ethereum protocols:', protocols.ethereum.length);
    console.log('Arbitrum protocols:', protocols.arbitrum.length);
    ```
  </Tab>

  <Tab title="Search Protocols" icon="magnifying-glass">
    Client-side filtering of protocol results:

    ```javascript theme={null}
    async function searchProtocols(chainKey, query) {
      // Fetch all protocols (the API does not expose server-side search)
      const allProtocols = await getAllProtocols(chainKey);

      const lowerQuery = query.toLowerCase();
      return allProtocols.filter(p =>
        p.name.toLowerCase().includes(lowerQuery) ||
        p.key.toLowerCase().includes(lowerQuery)
      );
    }

    const results = await searchProtocols('ethereum', 'uniswap');
    // => [{ name: "Uniswap V2", ... }, { name: "Uniswap V3", ... }]
    ```
  </Tab>
</Tabs>

***

## Error Responses

<AccordionGroup>
  <Accordion title="400 Bad Request" icon="circle-exclamation">
    Invalid query parameters.

    ```json theme={null}
    {
      "error": "Validation Failed",
      "details": {
        "message": "\"limit\" must be less than or equal to 100"
      }
    }
    ```

    **Common causes:**

    * `page` is less than 1
    * `limit` exceeds 100
  </Accordion>

  <Accordion title="401 Unauthorized" icon="lock">
    Authentication failed.

    ```json theme={null}
    {
      "error": "Unauthorized",
      "message": "Invalid API key"
    }
    ```

    **Solution:** Check your API key in the Authorization header
  </Accordion>

  <Accordion title="404 Not Found" icon="circle-question">
    The specified chain key does not exist.

    ```json theme={null}
    {
      "message": "Chain with key 'xyz' not found"
    }
    ```

    **Solution:** Use the [Chains](/api/endpoints/chains) endpoint to discover valid chain keys
  </Accordion>

  <Accordion title="429 Too Many Requests" icon="gauge-high">
    Rate limit exceeded.

    ```json theme={null}
    {
      "error": "Rate limit exceeded",
      "message": "You have exceeded your rate limit",
      "retry_after": 60
    }
    ```

    **Solution:** Wait for the specified time or implement retry logic
  </Accordion>
</AccordionGroup>

***

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Chains" icon="link-simple" href="/api/endpoints/chains">
    Get all supported chains and their keys
  </Card>

  <Card title="Portfolio" icon="wallet" href="/api/endpoints/portfolio">
    Get portfolio holdings by protocol
  </Card>

  <Card title="Protocol Types Reference" icon="layer-group" href="/api/reference/protocol-types">
    View all protocol type categories
  </Card>

  <Card title="Transactions" icon="receipt" href="/api/endpoints/transactions">
    Query transactions filtered by protocol
  </Card>
</CardGroup>
