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

# The Complete Developer Guide

> Build DeFi dashboards, portfolio trackers, and AI-powered crypto agents using the Octav API, MCP Server, CLI, and x402 payments. Complete guide with code examples.

Build a DeFi dashboard, alert system, or portfolio tracker with the Octav API. This guide walks through four real projects — from a vibecoded React dashboard to an autonomous AI agent — using every tool in the Octav developer ecosystem.

<Info>
  **What you'll build:** A real-time portfolio dashboard, a transaction alert system, an AI portfolio agent, and a tax export tool — all powered by the same API.
</Info>

***

## Why Octav?

Building crypto apps normally means stitching together 10+ APIs, normalizing data across chains, and maintaining a patchwork of indexers. Octav replaces all of that with a single API covering 65+ blockchains.

<CardGroup cols={2}>
  <Card title="One API, 65+ Chains" icon="link">
    Portfolio, transactions, DeFi positions, and historical data — all from one endpoint
  </Card>

  <Card title="Multiple Access Methods" icon="toolbox">
    REST API, MCP Server, CLI, x402 payments, Agent Skill, and llms.txt — pick the tool that fits your workflow
  </Card>

  <Card title="1-Credit Calls" icon="coins">
    Most calls cost 1 credit (\$0.025). Credits never expire. No subscriptions.
  </Card>

  <Card title="AI-Native" icon="robot">
    Built for vibecoding — structured JSON output, LLM-friendly docs, and MCP integration
  </Card>
</CardGroup>

### Architecture

Octav sits between the blockchain data layer and your application:

```
65+ Blockchains (EVM + Solana)
        |
    [Octav API]  <-- indexing, normalization, caching
        |
   +---------+---------+---------+
   |         |         |         |
REST API   MCP     CLI       x402
   |       Server    |       Payments
   |         |       |         |
Your App  Claude  Shell     AI Agents
          Cursor  Scripts   (no API key)
          VS Code  Cron
```

***

## Getting Started

Get your API key and make your first request in under 3 minutes.

<Steps>
  <Step title="Get an API Key" icon="key">
    Sign up at [data.octav.fi](https://data.octav.fi/) and generate an API key. Purchase a credit package — the Starter pack (4,000 credits / \$100) is plenty for testing.
  </Step>

  <Step title="Make Your First Request" icon="code">
    Fetch the net worth of any wallet address:

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

      ```javascript JavaScript theme={null}
      const response = await fetch(
        'https://api.octav.fi/v1/nav?addresses=0x6426af179aabebe47666f345d69fd9079673f6cd',
        { headers: { 'Authorization': `Bearer ${process.env.OCTAV_API_KEY}` } }
      );

      const data = await response.json();
      console.log(`Net Worth: $${data.nav}`);
      // => Net Worth: $1,235,564.43
      ```

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

      response = requests.get(
          'https://api.octav.fi/v1/nav',
          params={'addresses': '0x6426af179aabebe47666f345d69fd9079673f6cd'},
          headers={'Authorization': f'Bearer {api_key}'}
      )

      data = response.json()
      print(f"Net Worth: ${data['nav']:,.2f}")
      # => Net Worth: $1,235,564.43
      ```
    </CodeGroup>
  </Step>

  <Step title="Explore the Endpoints" icon="map">
    The core endpoints you'll use across all four projects:

    | Endpoint             | What It Returns                    | Cost     |
    | -------------------- | ---------------------------------- | -------- |
    | `/v1/portfolio`      | Full portfolio with DeFi positions | 1 credit |
    | `/v1/nav`            | Net asset value in any currency    | 1 credit |
    | `/v1/wallet`         | Token balances (no DeFi)           | 1 credit |
    | `/v1/transactions`   | Transaction history with filters   | 1 credit |
    | `/v1/token-overview` | Token distribution across chains   | 1 credit |
    | `/v1/historical`     | Portfolio snapshot at a past date  | 1 credit |
    | `/v1/credits`        | Your remaining credits             | Free     |
    | `/v1/status`         | Sync status for addresses          | Free     |
  </Step>
</Steps>

***

## Project 1: Real-Time Portfolio Dashboard

Build a React dashboard that shows net worth, DeFi positions, and token distribution — using a prompt-first approach.

### The Vibecoding Prompt

Give this prompt to Claude, Cursor, or your AI coding assistant of choice:

```text theme={null}
Using the Octav API (docs: https://api-docs.octav.fi/llms.txt), build a React + TypeScript
portfolio dashboard with TailwindCSS.

Features:
- Input field for wallet address (EVM 0x... or Solana base58)
- Net worth display using GET /v1/nav?addresses={addr}
- DeFi positions grouped by protocol using GET /v1/portfolio?addresses={addr}
- Token distribution pie chart using GET /v1/token-overview?addresses={addr}&date={today}
- Loading states and error handling

Auth: Bearer token via OCTAV_API_KEY env var, proxied through a Next.js API route.
All Octav endpoints return JSON. Portfolio response includes networth, chains, and assetByProtocols.
```

<Tip>
  **MCP superpower:** Install the [MCP Server](/api/ai-development/mcp-server) and your AI assistant can query live portfolio data *while* building the dashboard. It sees real response shapes, not just docs.
</Tip>

### The Dashboard Component

Here's what the AI generates (and what you'd refine):

```typescript theme={null}
import { useState, useEffect } from 'react';

interface Portfolio {
  networth: string;
  chains: Record<string, { name: string; value: string }>;
  assetByProtocols: Record<string, {
    name: string;
    value: string;
    protocolImage: string;
    positions: Array<{
      type: string;
      assets: Array<{ symbol: string; value: string; balance: string }>;
    }>;
  }>;
}

interface NavData {
  nav: number;
  currency: string;
}

interface TokenOverview {
  tokens: Array<{ symbol: string; value: number; percentage: number }>;
}

export function PortfolioDashboard({ address }: { address: string }) {
  const [portfolio, setPortfolio] = useState<Portfolio | null>(null);
  const [nav, setNav] = useState<NavData | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!address) return;

    async function fetchData() {
      setLoading(true);
      setError(null);

      try {
        const headers = { 'Authorization': `Bearer ${process.env.NEXT_PUBLIC_OCTAV_API_KEY}` };

        const [portfolioRes, navRes] = await Promise.all([
          fetch(`https://api.octav.fi/v1/portfolio?addresses=${address}`, { headers }),
          fetch(`https://api.octav.fi/v1/nav?addresses=${address}`, { headers }),
        ]);

        if (!portfolioRes.ok || !navRes.ok) {
          throw new Error('Failed to fetch portfolio data');
        }

        const [portfolioData, navData] = await Promise.all([
          portfolioRes.json(),
          navRes.json(),
        ]);

        setPortfolio(portfolioData[0]);
        setNav(navData);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Unknown error');
      } finally {
        setLoading(false);
      }
    }

    fetchData();
  }, [address]);

  if (loading) return <div className="animate-pulse">Loading portfolio...</div>;
  if (error) return <div className="text-red-500">Error: {error}</div>;
  if (!portfolio || !nav) return null;

  return (
    <div className="space-y-6">
      {/* Net Worth */}
      <div className="bg-gray-900 rounded-xl p-6">
        <p className="text-gray-400 text-sm">Net Worth</p>
        <p className="text-4xl font-bold text-white">
          ${nav.nav.toLocaleString(undefined, { maximumFractionDigits: 2 })}
        </p>
      </div>

      {/* Chain Distribution */}
      <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
        {Object.values(portfolio.chains).map((chain) => (
          <div key={chain.name} className="bg-gray-800 rounded-lg p-4">
            <p className="text-gray-400 text-sm">{chain.name}</p>
            <p className="text-white font-semibold">
              ${parseFloat(chain.value).toLocaleString(undefined, { maximumFractionDigits: 0 })}
            </p>
          </div>
        ))}
      </div>

      {/* DeFi Positions by Protocol */}
      <div className="space-y-4">
        <h2 className="text-xl font-bold text-white">DeFi Positions</h2>
        {Object.values(portfolio.assetByProtocols).map((protocol) => (
          <div key={protocol.name} className="bg-gray-800 rounded-lg p-4">
            <div className="flex justify-between items-center mb-2">
              <span className="text-white font-semibold">{protocol.name}</span>
              <span className="text-gray-400">
                ${parseFloat(protocol.value).toLocaleString(undefined, { maximumFractionDigits: 0 })}
              </span>
            </div>
            {protocol.positions.map((position, i) => (
              <div key={i} className="ml-4 text-sm text-gray-400">
                <span className="uppercase text-xs text-gray-500">{position.type}</span>
                {position.assets.map((asset, j) => (
                  <div key={j} className="flex justify-between">
                    <span>{asset.symbol}</span>
                    <span>${parseFloat(asset.value).toLocaleString()}</span>
                  </div>
                ))}
              </div>
            ))}
          </div>
        ))}
      </div>
    </div>
  );
}
```

<Tip>
  **Security:** In production, proxy API calls through your backend. Never expose `OCTAV_API_KEY` in client-side code. Use a Next.js API route or similar server-side proxy.
</Tip>

***

## Project 2: Transaction Alert System

Build a whale-alert style notification system using the Octav CLI and cron. No Node.js runtime, no dependencies — just bash.

### Install the CLI

```bash theme={null}
curl -sSf https://raw.githubusercontent.com/Octav-Labs/octav-cli/main/install.sh | sh
octav auth set-key YOUR_API_KEY
```

### The Alert Script

```bash theme={null}
#!/bin/bash
# tx-alert.sh — Monitor wallets for new transactions, alert on large ones

ADDRESSES="0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68"
THRESHOLD_USD=1000
STATE_DIR="$HOME/.octav/state"
LOG_FILE="$HOME/.octav/logs/tx-alert.log"

mkdir -p "$STATE_DIR" "$(dirname "$LOG_FILE")"

for ADDR in $(echo "$ADDRESSES" | tr ',' '\n'); do
  STATE_FILE="$STATE_DIR/last-tx-${ADDR:0:8}.txt"
  LAST_SEEN=""
  [ -f "$STATE_FILE" ] && LAST_SEEN=$(cat "$STATE_FILE")

  # Fetch recent transactions
  RESULT=$(octav transactions get --addresses "$ADDR" --limit 20 --raw 2>&1)
  if [ $? -ne 0 ]; then
    echo "[$(date)] ERROR fetching $ADDR: $RESULT" >> "$LOG_FILE"
    continue
  fi

  LATEST_TX=$(echo "$RESULT" | jq -r '.transactions[0].hash // empty')
  [ -z "$LATEST_TX" ] && continue

  # Skip if no new transactions
  [ "$LATEST_TX" = "$LAST_SEEN" ] && continue

  # Process new transactions
  echo "$RESULT" | jq -r --arg last "$LAST_SEEN" --argjson threshold "$THRESHOLD_USD" '
    .transactions
    | if $last == "" then .[:5] else [limit(20; .[] | select(.hash != $last))] end
    | .[]
    | select(
        [.assets[]? | .value // 0 | tonumber] | add > $threshold
      )
    | "[\(.date)] \(.txType) $\([.assets[]? | .value // 0 | tonumber] | add | floor) on \(.chainKey) — \(.hash[:16])..."
  ' | while read -r line; do
    echo "$line" >> "$LOG_FILE"
    # macOS notification
    osascript -e "display notification \"$line\" with title \"Octav Alert\"" 2>/dev/null
  done

  # Update state
  echo "$LATEST_TX" > "$STATE_FILE"
done
```

### Schedule It

<Tabs>
  <Tab title="cron" icon="clock">
    ```bash theme={null}
    # Check every 10 minutes
    */10 * * * * /path/to/tx-alert.sh
    ```

    Add with:

    ```bash theme={null}
    (crontab -l 2>/dev/null; echo "*/10 * * * * $HOME/scripts/tx-alert.sh") | crontab -
    ```
  </Tab>

  <Tab title="launchd (macOS)" icon="apple">
    Save as `~/Library/LaunchAgents/fi.octav.tx-alert.plist`:

    ```xml theme={null}
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
      "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>Label</key>
      <string>fi.octav.tx-alert</string>
      <key>ProgramArguments</key>
      <array>
        <string>/bin/bash</string>
        <string>/Users/YOU/scripts/tx-alert.sh</string>
      </array>
      <key>StartInterval</key>
      <integer>600</integer>
      <key>StandardOutPath</key>
      <string>/tmp/tx-alert.stdout</string>
      <key>StandardErrorPath</key>
      <string>/tmp/tx-alert.stderr</string>
    </dict>
    </plist>
    ```

    ```bash theme={null}
    launchctl load ~/Library/LaunchAgents/fi.octav.tx-alert.plist
    ```
  </Tab>
</Tabs>

### Customize with AI

Give Claude Code this prompt to extend the script:

```text theme={null}
I have a bash script that monitors crypto wallets using the octav CLI.
It currently sends macOS notifications. Modify it to:
1. Send alerts to a Slack webhook (URL in SLACK_WEBHOOK env var)
2. Filter to only swap and transfer transactions
3. Add a daily summary at midnight with total transaction count and volume
```

***

## Project 3: AI Portfolio Agent

Connect the Octav MCP Server to your AI assistant and build an autonomous monitoring agent.

### Set Up MCP

<Tabs>
  <Tab title="Claude Desktop" icon="comment">
    Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:

    ```json theme={null}
    {
      "mcpServers": {
        "octav": {
          "command": "npx",
          "args": ["-y", "octav-api-mcp"],
          "env": {
            "OCTAV_API_KEY": "your-api-key-here"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Cursor" icon="code">
    Go to **Cursor Settings > MCP** and add:

    ```json theme={null}
    {
      "mcpServers": {
        "octav": {
          "command": "npx",
          "args": ["-y", "octav-api-mcp"],
          "env": {
            "OCTAV_API_KEY": "your-api-key-here"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="VS Code (Copilot)" icon="microsoft">
    Add to your VS Code `settings.json`:

    ```json theme={null}
    {
      "mcp": {
        "servers": {
          "octav": {
            "command": "npx",
            "args": ["-y", "octav-api-mcp"],
            "env": {
              "OCTAV_API_KEY": "your-api-key-here"
            }
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Claude Code" icon="terminal">
    ```bash theme={null}
    claude mcp add octav -- npx -y octav-api-mcp
    ```

    Then set the API key via your shell profile:

    ```bash theme={null}
    export OCTAV_API_KEY="your-api-key-here"
    ```
  </Tab>
</Tabs>

### Natural Language Queries

Once connected, ask your AI assistant questions like:

```text theme={null}
"What's my total exposure to Aave across all chains for 0xABC...?"
```

```text theme={null}
"Show me all swap transactions over $1,000 on Arbitrum in the last 30 days"
```

```text theme={null}
"Compare my portfolio value today vs. 30 days ago and tell me which chains gained the most"
```

The MCP server exposes 14 tools — your AI assistant can call `octav_get_portfolio`, `octav_get_transactions`, `octav_get_nav`, and more directly from conversation.

### Python Monitoring Agent

For autonomous monitoring, build a Python agent:

```python theme={null}
import requests
import time
import os
from datetime import datetime, timedelta

class OctavPortfolioAgent:
    """Autonomous portfolio monitor using the Octav API"""

    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = 'https://api.octav.fi/v1'
        self.headers = {'Authorization': f'Bearer {api_key}'}
        self.snapshots: dict[str, float] = {}

    def get_nav(self, address: str, currency: str = 'USD') -> dict:
        """Get net asset value"""
        resp = requests.get(
            f'{self.base_url}/nav',
            params={'addresses': address, 'currency': currency},
            headers=self.headers,
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()

    def get_portfolio(self, address: str) -> dict:
        """Get full portfolio with DeFi positions"""
        resp = requests.get(
            f'{self.base_url}/portfolio',
            params={'addresses': address},
            headers=self.headers,
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()[0]

    def get_transactions(self, address: str, **filters) -> list:
        """Get transaction history with optional filters"""
        params = {'addresses': address, **filters}
        resp = requests.get(
            f'{self.base_url}/transactions',
            params=params,
            headers=self.headers,
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()

    def check_credits(self) -> int:
        """Check remaining API credits"""
        resp = requests.get(
            f'{self.base_url}/credits',
            headers=self.headers,
        )
        return resp.json().get('credits', 0)

    def monitor(self, addresses: list[str], interval: int = 300, threshold_pct: float = 5.0):
        """Main monitoring loop — checks portfolio and alerts on changes"""
        print(f"Monitoring {len(addresses)} address(es) every {interval}s")
        print(f"Alert threshold: {threshold_pct}% change")
        print(f"Credits remaining: {self.check_credits()}")

        while True:
            for addr in addresses:
                try:
                    nav = self.get_nav(addr)
                    current = nav['nav']
                    previous = self.snapshots.get(addr)

                    if previous:
                        change_pct = ((current - previous) / previous) * 100
                        if abs(change_pct) >= threshold_pct:
                            print(f"\n{'='*50}")
                            print(f"ALERT: {addr[:10]}... changed {change_pct:+.2f}%")
                            print(f"  ${previous:,.2f} -> ${current:,.2f}")
                            print(f"  {datetime.now().isoformat()}")
                            print(f"{'='*50}\n")

                    self.snapshots[addr] = current
                    time.sleep(2)  # rate limit courtesy

                except requests.RequestException as e:
                    print(f"Error checking {addr[:10]}...: {e}")

            time.sleep(interval)


if __name__ == '__main__':
    agent = OctavPortfolioAgent(os.environ['OCTAV_API_KEY'])

    agent.monitor(
        addresses=['0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68'],
        interval=300,
        threshold_pct=3.0,
    )
```

### x402 Agent Payments

For autonomous AI agents that don't have API keys, use the x402 payment protocol. The agent pays per request with USDC — no key management needed.

```python theme={null}
# x402 agent call — no API key required
# The agent's wallet pays via HTTP 402 payment protocol
import requests

response = requests.get(
    'https://api.octav.fi/v1/agent/wallet?addresses=0x742d35Cc...',
    # No Authorization header needed — payment handled via x402
)

# If 402 is returned, the agent's x402-compatible HTTP client
# automatically handles the micropayment and retries
data = response.json()
```

Via the CLI:

```bash theme={null}
# No API key needed — pays with x402
octav agent wallet --addresses 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68
octav agent portfolio --addresses 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68
```

***

## Project 4: Tax & Accounting Export Tool

Export categorized transaction history to CSV for tax reporting.

```python theme={null}
import requests
import csv
import os
from datetime import datetime

class TaxExporter:
    """Export transaction history to CSV for tax reporting"""

    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = 'https://api.octav.fi/v1'
        self.headers = {'Authorization': f'Bearer {api_key}'}

    # Transaction type categories for tax purposes
    TAX_CATEGORIES = {
        'SWAP': 'Trade',
        'TRANSFERIN': 'Receive',
        'TRANSFEROUT': 'Send',
        'CLAIM': 'Income',
        'AIRDROP': 'Income',
        'STAKE': 'DeFi',
        'UNSTAKE': 'DeFi',
        'DEPOSIT': 'DeFi',
        'WITHDRAW': 'DeFi',
        'BORROW': 'DeFi',
        'REPAY': 'DeFi',
        'APPROVE': 'Other',
    }

    def fetch_all_transactions(self, address: str, start_date: str, end_date: str) -> list:
        """Fetch all transactions with pagination"""
        all_txs = []
        offset = 0
        limit = 250

        while True:
            resp = requests.get(
                f'{self.base_url}/transactions',
                params={
                    'addresses': address,
                    'startDate': start_date,
                    'endDate': end_date,
                    'limit': limit,
                    'offset': offset,
                    'sort': 'ASC',
                },
                headers=self.headers,
                timeout=30,
            )
            resp.raise_for_status()
            data = resp.json()

            txs = data if isinstance(data, list) else data.get('transactions', [])
            if not txs:
                break

            all_txs.extend(txs)
            if len(txs) < limit:
                break

            offset += limit

        return all_txs

    def export_csv(self, address: str, year: int, output_path: str):
        """Export a full year of transactions to CSV"""
        start_date = f'{year}-01-01'
        end_date = f'{year}-12-31'

        print(f"Fetching transactions for {address[:10]}... ({start_date} to {end_date})")
        transactions = self.fetch_all_transactions(address, start_date, end_date)
        print(f"Found {len(transactions)} transactions")

        with open(output_path, 'w', newline='') as f:
            writer = csv.writer(f)
            writer.writerow([
                'Date', 'Type', 'Tax Category', 'Chain',
                'Asset', 'Amount', 'Value (USD)',
                'Fee (USD)', 'Transaction Hash',
            ])

            for tx in transactions:
                tx_type = tx.get('txType', 'UNKNOWN')
                tax_category = self.TAX_CATEGORIES.get(tx_type, 'Other')
                fee_usd = sum(float(f.get('value', 0)) for f in tx.get('fees', []))

                for asset in tx.get('assets', []):
                    writer.writerow([
                        tx.get('date', ''),
                        tx_type,
                        tax_category,
                        tx.get('chainKey', ''),
                        asset.get('symbol', ''),
                        asset.get('balance', ''),
                        asset.get('value', ''),
                        f'{fee_usd:.2f}',
                        tx.get('hash', ''),
                    ])

        print(f"Exported to {output_path}")


if __name__ == '__main__':
    exporter = TaxExporter(os.environ['OCTAV_API_KEY'])

    exporter.export_csv(
        address='0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68',
        year=2025,
        output_path='crypto-taxes-2025.csv',
    )
```

### Historical Snapshots

For year-end portfolio valuations, use the historical endpoint with subscribe-snapshot for automatic daily recording:

```bash theme={null}
# Subscribe to daily snapshots (one-time setup)
octav historical subscribe-snapshot \
  --addresses 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68 \
  --description "Tax reporting - main wallet"

# Later, pull a specific date's snapshot
octav historical get \
  --addresses 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68 \
  --date 2025-12-31
```

***

## Developer Toolkit Overview

Choose the right tool for your use case:

| Tool              | Best For                                     | Setup                                       | Auth                |
| ----------------- | -------------------------------------------- | ------------------------------------------- | ------------------- |
| **REST API**      | Web apps, backends, integrations             | Any HTTP client                             | API key             |
| **MCP Server**    | AI assistants (Claude, Cursor, VS Code)      | `npx octav-api-mcp`                         | API key             |
| **CLI**           | Shell scripts, cron jobs, terminal workflows | `curl \| sh` or `cargo install octav`       | API key or env var  |
| **x402 Payments** | Autonomous AI agents                         | No setup                                    | Agent wallet (USDC) |
| **Agent Skill**   | Claude Code, Codex, ChatGPT                  | `npx skills add Octav-Labs/octav-api-skill` | API key             |
| **llms.txt**      | Feed docs to any LLM                         | Point to URL                                | N/A                 |

<Tabs>
  <Tab title="REST API" icon="code">
    Direct HTTP calls to `https://api.octav.fi/v1/`. Works with any language or framework. 65+ chains, 1-credit calls, structured JSON responses.

    ```bash theme={null}
    curl -X GET "https://api.octav.fi/v1/portfolio?addresses=0xABC..." \
      -H "Authorization: Bearer YOUR_API_KEY"
    ```
  </Tab>

  <Tab title="MCP Server" icon="plug">
    14 tools accessible through natural language in Claude Desktop, Cursor, VS Code, and Claude Code.

    ```bash theme={null}
    npx octav-api-mcp
    ```

    [Full MCP docs](/api/ai-development/mcp-server)
  </Tab>

  <Tab title="CLI" icon="terminal">
    Rust binary with structured JSON output. Ideal for shell scripts and AI agent tool-use.

    ```bash theme={null}
    octav portfolio nav --addresses 0xABC... --raw | jq '.nav'
    ```

    [Full CLI docs](/api/ai-development/cli)
  </Tab>

  <Tab title="x402 Payments" icon="credit-card">
    HTTP 402 payment protocol for AI agents. No API keys — the agent pays per request with USDC.

    ```bash theme={null}
    octav agent portfolio --addresses 0xABC...
    ```
  </Tab>

  <Tab title="Agent Skill" icon="robot">
    Install once and your AI agent knows the full API:

    ```bash theme={null}
    npx skills add Octav-Labs/octav-api-skill
    ```

    [View on skills.sh](https://skills.sh/Octav-Labs/octav-api-skill)
  </Tab>

  <Tab title="llms.txt" icon="file">
    Feed structured API docs directly to any LLM:

    ```text theme={null}
    https://api-docs.octav.fi/llms.txt
    ```

    [Learn more](/api/ai-development/llms-integration)
  </Tab>
</Tabs>

***

## Advanced Patterns

### Multi-Wallet Aggregation

Query up to 10 addresses in a single API call (still just 1 credit per address):

```python theme={null}
addresses = '0xABC...,0xDEF...,0x123...'
response = requests.get(
    f'https://api.octav.fi/v1/portfolio?addresses={addresses}',
    headers={'Authorization': f'Bearer {api_key}'}
)

# Returns an array — one portfolio object per address
portfolios = response.json()
total_nav = sum(float(p['networth']) for p in portfolios)
```

### Rate Limit Handling

The API allows 360 requests per minute. Implement exponential backoff for reliability:

```python theme={null}
import time
from requests.exceptions import RequestException

def fetch_with_retry(url: str, headers: dict, max_retries: int = 3):
    for attempt in range(max_retries):
        try:
            resp = requests.get(url, headers=headers, timeout=30)
            if resp.status_code == 429:
                wait = int(resp.headers.get('Retry-After', 2 ** attempt))
                time.sleep(wait)
                continue
            resp.raise_for_status()
            return resp.json()
        except RequestException:
            if attempt == max_retries - 1:
                raise
            time.sleep(2 ** attempt)
```

### Dust Filtering

Filter out small token balances that clutter portfolio views:

```python theme={null}
portfolio = response.json()[0]

# Filter tokens worth less than $1
meaningful_tokens = {
    key: protocol
    for key, protocol in portfolio['assetByProtocols'].items()
    if float(protocol['value']) > 1.0
}
```

### Webhook-Style Polling

Combine the CLI with cron for webhook-like behavior without running a server:

```bash theme={null}
# Check every 5 minutes, alert on changes
*/5 * * * * /path/to/portfolio-monitor.sh

# Daily snapshot at 9am
0 9 * * * /path/to/daily-snapshot.sh

# Weekly report on Sundays
0 10 * * 0 /path/to/weekly-report.sh
```

See [CLI Automations](/cli/automations) for complete, production-ready scripts.

***

## What's Next

<CardGroup cols={2}>
  <Card title="API Reference" icon="book" href="/api/introduction">
    Complete endpoint documentation with interactive playground
  </Card>

  <Card title="MCP Server" icon="plug" href="/api/ai-development/mcp-server">
    Connect AI assistants to live portfolio data
  </Card>

  <Card title="CLI Automations" icon="terminal" href="/cli/automations">
    Production-ready cron scripts for monitoring and exports
  </Card>

  <Card title="Pricing" icon="tag" href="/api/pricing">
    Credit packages starting at \$100 for 4,000 calls
  </Card>
</CardGroup>

<Info>
  **Ready to start?** Get your API key at [data.octav.fi](https://data.octav.fi/) and build your first project in minutes. Join the [Discord](https://discord.com/invite/qvcknAa73A) if you need help.
</Info>
