Guides

Building with the API

TypeScript and Python code examples for fetching vaults, filtering by risk tier, and building dashboards with the Philidor API.

TypeScript: Fetch and Filter Vaults

interface Vault {
  id: string;
  name: string;
  total_score: string | number | null;
  risk_tier: string;
  apr_net: number | null;
  tvl_usd: number;
  chain_name: string;
  protocol_name: string;
}

async function getPrimeVaults(asset: string): Promise<Vault[]> {
  const res = await fetch(
    `https://api.philidor.io/v1/vaults?riskTier=prime&asset=${asset}&sortBy=apr_net&sortOrder=desc`
  );
  const { data } = await res.json();
  return data;
}

const vaults = await getPrimeVaults('USDC');
for (const v of vaults) {
  console.log(`${v.name}: score=${v.total_score}, APR=${((v.apr_net ?? 0) * 100).toFixed(2)}%`);
}

Python: Daily Risk Monitor

import requests
import json
from datetime import datetime

API = "https://api.philidor.io/v1"

def check_portfolio(address: str):
    res = requests.get(f"{API}/address/{address}/positions")
    data = res.json()["data"]

    print(f"Portfolio: {address}")
    print(f"Total value: USD {float(data['aggregates']['total_value_usd']):,.0f}")
    print(f"Weighted risk: {data['aggregates']['weighted_risk_score']:.1f}")
    print()

    for pos in data["positions"]:
        score = pos.get("risk_score")
        tier = pos.get("risk_tier", "Unrated")
        flag = " monitor" if score is not None and score < 5 else ""
        score_label = f"{score:.1f}" if score is not None else "unrated"
        print(f"  {pos['vault_name']}: {score_label} ({tier}){flag}")

check_portfolio("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

Error Handling

async function fetchVault(network: string, address: string) {
  const res = await fetch(`https://api.philidor.io/v1/vault/${network}/${address}`);

  if (res.status === 404) {
    throw new Error(`Vault not found: ${network}/${address}`);
  }
  if (res.status === 429) {
    const retryAfter = res.headers.get('Retry-After');
    throw new Error(`Rate limited. Retry after ${retryAfter}s`);
  }
  if (!res.ok) {
    const body = await res.json();
    throw new Error(body.error?.message || `HTTP ${res.status}`);
  }

  const { data } = await res.json();
  return data;
}

Rate Limit Considerations

  • Public endpoints allow 30 requests per minute per IP without an API key
  • Use pagination (page + limit) instead of fetching all vaults at once
  • Cache responses where possible because vault data updates on hourly sync cycles and incident-triggered rescoring can arrive sooner
  • The API returns X-RateLimit-Limit and X-RateLimit-Window headers

Extended API Access

The public read API is available without authentication. Public /v1 read endpoints support evaluation, research, and development out of the box.

For production integrations that need higher rate limits, dedicated API keys, webhooks, or agreement-defined service commitments, contact Philidor to discuss your use case. See API Access and Plans for plan details.

Contact @zdeadex on Telegram or contact@philidor.io

Pagination

async function getAllVaults(): Promise<Vault[]> {
  const all: Vault[] = [];
  let page = 1;

  while (true) {
    const res = await fetch(`https://api.philidor.io/v1/vaults?page=${page}&limit=50`);
    const { data, meta } = await res.json();
    all.push(...data);

    if (page >= meta.totalPages) break;
    page++;
  }

  return all;
}

On this page

Raw