> ## 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.

# Token Approvals

> Retrieve ERC-20 token approval records for a wallet on a given chain

Retrieve ERC-20 token approval (allowance) records for a wallet on a specific chain. Each approval represents a transaction where the wallet granted a spender contract permission to transfer tokens on its behalf.

<Info>
  **Cost:** 1 credit per call (WALLET credits)
</Info>

<Note>
  **Interactive Playground:** Test this endpoint in the [API Playground](/api-reference/approvals). 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/approvals/:chain
  ```

  ```bash Example theme={null}
  curl -X GET "https://api.octav.fi/v1/approvals/ethereum?addresses=0x6426af179aabebe47666f345d69fd9079673f6cd&limit=25" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```
</CodeGroup>

***

## Path Parameters

<ParamField path="chain" type="string" required>
  Chain identifier

  Supported chains: `arbitrum`, `avalanche`, `base`, `binance`, `ethereum`, `fantom`, `gnosis`, `linea`, `optimism`, `polygon`

  See [Supported Blockchains](/docs/supported-blockchains) for details
</ParamField>

***

## Required Parameters

<ParamField query="addresses" type="string" required>
  Wallet address to fetch approvals for

  ```
  addresses=0x6426af179aabebe47666f345d69fd9079673f6cd
  ```
</ParamField>

***

## Optional Parameters

<ParamField query="limit" type="integer" default="25">
  Number of results per page

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

<ParamField query="cursor" type="string">
  Cursor string from a previous response to fetch the next page

  ```
  cursor=eyJhbGciOiJIUzI1NiJ9...
  ```
</ParamField>

***

## Response

### Top-Level Fields

<ResponseField name="cursor" type="string|null">
  Cursor for the next page. `null` or absent when there are no more results.
</ResponseField>

<ResponseField name="pageSize" type="number">
  Number of items returned in this page.
</ResponseField>

<ResponseField name="items" type="array">
  Array of token approval records.
</ResponseField>

### Approval Object

Each item in `items` contains:

<ResponseField name="block" type="string">
  Block number where the approval transaction was mined.
</ResponseField>

<ResponseField name="timestamp" type="string">
  ISO 8601 timestamp of the block.
</ResponseField>

<ResponseField name="hash" type="string">
  Transaction hash of the approval.
</ResponseField>

<ResponseField name="contract" type="string">
  Address of the token contract that was approved.
</ResponseField>

<ResponseField name="from" type="string">
  Wallet address that granted the approval.
</ResponseField>

<ResponseField name="to" type="string">
  Spender address that received the approval.
</ResponseField>

<ResponseField name="amount" type="string">
  Raw approved amount (not decimal-adjusted). A max `uint256` value indicates unlimited approval.
</ResponseField>

<ResponseField name="asset" type="object">
  Enriched token metadata. Present only when the token is tracked in the Octav asset database.

  Contains: `name`, `symbol`, `balance`, `price`, `value`, `decimal`, `chain`, `contract`, `imgSmall`, `imgLarge`

  Follows the standard `AssetViewModel` shape used across other Octav API responses.
</ResponseField>

***

## Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.octav.fi/v1/approvals/ethereum?addresses=0x6426af179aabebe47666f345d69fd9079673f6cd&limit=25" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const chain = 'ethereum';
  const address = '0x6426af179aabebe47666f345d69fd9079673f6cd';

  const params = new URLSearchParams({
    addresses: address,
    limit: '25'
  });

  const response = await fetch(
    `https://api.octav.fi/v1/approvals/${chain}?${params}`,
    {
      headers: {
        'Authorization': `Bearer ${apiKey}`
      }
    }
  );

  const data = await response.json();
  console.log(`Found ${data.items.length} approvals`);
  ```

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

  chain = 'ethereum'
  address = '0x6426af179aabebe47666f345d69fd9079673f6cd'

  response = requests.get(
      f'https://api.octav.fi/v1/approvals/{chain}',
      params={
          'addresses': address,
          'limit': 25
      },
      headers={'Authorization': f'Bearer {api_key}'}
  )

  data = response.json()
  print(f"Found {len(data['items'])} approvals")
  ```

  ```typescript TypeScript theme={null}
  interface Asset {
    name: string;
    symbol: string;
    balance: string;
    price: string;
    value: string;
    decimal: string;
    chain: string;
    contract: string;
    imgSmall?: string;
    imgLarge?: string;
  }

  interface Approval {
    block: string;
    timestamp: string;
    hash: string;
    contract: string;
    from: string;
    to: string;
    amount: string;
    asset?: Asset;
  }

  interface ApprovalsResponse {
    cursor: string | null;
    pageSize: number;
    items: Approval[];
  }

  const chain = 'ethereum';
  const address = '0x6426af179aabebe47666f345d69fd9079673f6cd';

  const params = new URLSearchParams({
    addresses: address,
    limit: '25'
  });

  const response = await fetch(
    `https://api.octav.fi/v1/approvals/${chain}?${params}`,
    {
      headers: {
        'Authorization': `Bearer ${apiKey}`
      }
    }
  );

  const data: ApprovalsResponse = await response.json();
  console.log(`Found ${data.items.length} approvals`);
  ```
</CodeGroup>

***

## Example Response

<Accordion title="View Full Response" icon="code">
  ```json theme={null}
  {
    "cursor": "eyJhbGciOiJIUzI1NiJ9...",
    "pageSize": 25,
    "items": [
      {
        "block": "19432156",
        "timestamp": "2024-03-15T10:23:47.000Z",
        "hash": "0xa1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
        "contract": "0x6b175474e89094c44da98b954eedeac495271d0f",
        "from": "0x6426af179aabebe47666f345d69fd9079673f6cd",
        "to": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
        "amount": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
        "asset": {
          "name": "Dai Stablecoin",
          "symbol": "DAI",
          "balance": "1500.25",
          "price": "0.9998",
          "value": "1499.95",
          "decimal": "18",
          "chain": "ethereum",
          "contract": "0x6b175474e89094c44da98b954eedeac495271d0f",
          "imgSmall": "https://assets.coingecko.com/coins/images/9956/small/dai-multi-collateral-mcd.png",
          "imgLarge": "https://assets.coingecko.com/coins/images/9956/large/dai-multi-collateral-mcd.png"
        }
      },
      {
        "block": "19215432",
        "timestamp": "2024-02-10T14:05:22.000Z",
        "hash": "0xf9e8d7c6b5a4f9e8d7c6b5a4f9e8d7c6b5a4f9e8d7c6b5a4f9e8d7c6b5a4f9e8",
        "contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
        "from": "0x6426af179aabebe47666f345d69fd9079673f6cd",
        "to": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
        "amount": "50000000000",
        "asset": {
          "name": "USD Coin",
          "symbol": "USDC",
          "balance": "10234.50",
          "price": "1.0001",
          "value": "10235.52",
          "decimal": "6",
          "chain": "ethereum",
          "contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
          "imgSmall": "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png",
          "imgLarge": "https://assets.coingecko.com/coins/images/6319/large/USD_Coin_icon.png"
        }
      }
    ]
  }
  ```
</Accordion>

***

## Pagination

Use cursor-based pagination to iterate through results:

1. Make an initial request with just `limit` (or use the default of 25)
2. If the response contains a non-null `cursor`, pass it as the `cursor` query parameter in the next request
3. When `cursor` is `null` or absent, you have reached the end of the results

```javascript theme={null}
async function getAllApprovals(chain, address) {
  const approvals = [];
  let cursor = null;

  do {
    const params = new URLSearchParams({
      addresses: address,
      limit: '100'
    });
    if (cursor) params.set('cursor', cursor);

    const response = await fetch(
      `https://api.octav.fi/v1/approvals/${chain}?${params}`,
      {
        headers: {
          'Authorization': `Bearer ${apiKey}`
        }
      }
    );

    const data = await response.json();
    approvals.push(...data.items);
    cursor = data.cursor;
  } while (cursor);

  return approvals;
}
```

***

## Use Cases

<Tabs>
  <Tab title="Audit Approvals" icon="shield-halved">
    Review all active token approvals for security:

    ```javascript theme={null}
    const MAX_UINT256 = '115792089237316195423570985008687907853269984665640564039457584007913129639935';

    async function auditApprovals(chain, address) {
      const approvals = await getAllApprovals(chain, address);

      const unlimited = approvals.filter(a => a.amount === MAX_UINT256);
      const limited = approvals.filter(a => a.amount !== MAX_UINT256);

      console.log(`Total approvals: ${approvals.length}`);
      console.log(`Unlimited approvals: ${unlimited.length}`);
      console.log(`Limited approvals: ${limited.length}`);

      // Flag unlimited approvals for review
      unlimited.forEach(approval => {
        console.log(
          `UNLIMITED: ${approval.asset?.symbol || approval.contract} -> ${approval.to}`
        );
      });

      return { unlimited, limited };
    }
    ```
  </Tab>

  <Tab title="Multi-Chain Overview" icon="link">
    Scan approvals across all supported chains:

    ```javascript theme={null}
    const CHAINS = [
      'arbitrum', 'avalanche', 'base', 'binance',
      'ethereum', 'fantom', 'gnosis', 'linea',
      'optimism', 'polygon'
    ];

    async function getMultiChainApprovals(address) {
      const results = {};

      for (const chain of CHAINS) {
        const approvals = await getAllApprovals(chain, address);
        if (approvals.length > 0) {
          results[chain] = approvals;
          console.log(`${chain}: ${approvals.length} approvals`);
        }
      }

      return results;
    }
    ```
  </Tab>

  <Tab title="Track Approval Value" icon="dollar-sign">
    Calculate the total value of tokens with active approvals:

    ```javascript theme={null}
    async function calculateApprovalExposure(chain, address) {
      const approvals = await getAllApprovals(chain, address);
      let totalExposure = 0;

      approvals.forEach(approval => {
        if (approval.asset) {
          totalExposure += parseFloat(approval.asset.value);
          console.log(
            `${approval.asset.symbol}: $${approval.asset.value} approved to ${approval.to}`
          );
        }
      });

      console.log(`Total exposure: $${totalExposure.toFixed(2)}`);
      return totalExposure;
    }
    ```
  </Tab>

  <Tab title="Spender Analysis" icon="magnifying-glass">
    Group approvals by spender contract:

    ```javascript theme={null}
    async function analyzeSpenders(chain, address) {
      const approvals = await getAllApprovals(chain, address);

      const spenders = {};
      approvals.forEach(approval => {
        if (!spenders[approval.to]) {
          spenders[approval.to] = [];
        }
        spenders[approval.to].push(approval);
      });

      // Display spender summary
      Object.entries(spenders)
        .sort((a, b) => b[1].length - a[1].length)
        .forEach(([spender, apps]) => {
          const tokens = apps
            .map(a => a.asset?.symbol || 'Unknown')
            .join(', ');
          console.log(`${spender}: ${apps.length} tokens (${tokens})`);
        });

      return spenders;
    }
    ```
  </Tab>
</Tabs>

***

## Error Responses

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

    ```json theme={null}
    {
      "message": "chain must be one of: arbitrum, avalanche, base, binance, ethereum, fantom, gnosis, linea, optimism, polygon"
    }
    ```

    **Common causes:**

    * Invalid or unsupported chain in URL path
    * Missing `addresses` query parameter
    * `limit` out of range (must be 1-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="402 Payment Required" icon="credit-card">
    Insufficient credits.

    ```json theme={null}
    {
      "error": "Insufficient credits",
      "message": "Please purchase more credits to continue"
    }
    ```

    **Solution:** Purchase more credits at [data.octav.fi](https://data.octav.fi/)
  </Accordion>

  <Accordion title="502 Bad Gateway" icon="server">
    Upstream data provider is unavailable.

    ```json theme={null}
    {
      "message": "Failed to fetch token approvals from upstream provider"
    }
    ```

    **Solution:** Retry after a short delay. If the issue persists, the upstream provider may be experiencing an outage.
  </Accordion>
</AccordionGroup>

***

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Portfolio" icon="wallet" href="/api/endpoints/portfolio">
    View current portfolio holdings
  </Card>

  <Card title="Transactions" icon="receipt" href="/api/endpoints/transactions">
    Query full transaction history
  </Card>

  <Card title="Wallet" icon="building-columns" href="/api/endpoints/wallet">
    Get wallet balances across protocols
  </Card>

  <Card title="Token Overview" icon="coins" href="/api/endpoints/token-overview">
    Detailed token breakdown by protocol
  </Card>
</CardGroup>
