Skip to main content

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.

Query Ethereum beacon chain data for individual validators by index or BLS pubkey. All endpoints are read-only and source data from a self-hosted goteth ClickHouse instance via Octav’s beacon-svc (mainnet only).
Beacon validator endpoints are an add-on, billed at a set monthly fee separate from your API credit pool. Contact sales to enable beacon access for your account.
Cost: Set monthly fee under the beacon add-on — no per-call credit deduction.
Rate limit: 360 requests/min, shared with your portfolio bucket.

Path parameters

All endpoints accept one of two path-parameter forms:
ParameterTypeDescription
:indexintegerNon-negative validator index
:pubkeystring48-byte BLS pubkey, hex-encoded with 0x prefix (96 hex characters). Case-insensitive
Note: BLS pubkeys are validator identifiers, not wallet addresses.

Validator Details

Get current state, lifecycle epochs, effective balance, and withdrawal credentials for a single validator.

Endpoints

GET https://api.octav.fi/v1/beacon/validators/details/index/:index
GET https://api.octav.fi/v1/beacon/validators/details/pubkey/:pubkey

Response

validator
object
Core validator identity and status.
lifecycle
object
Epoch-level lifecycle milestones. Fields are null when not yet reached.
balance
object
Validator balances as wei strings.
withdrawalCredentials
object
Withdrawal credential info. address is only present for 0x01-prefix validators.

Example

curl "https://api.octav.fi/v1/beacon/validators/details/index/123456" \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "validator": {
    "index": 123456,
    "pubkey": "0xb03d97937ae39b38a44f90141dcf7f0420c3b9b21caee1a7603046bc9237f5c96b61714474249dafe0a20af583a4fc07",
    "slashed": false,
    "status": "active_ongoing"
  },
  "lifecycle": {
    "activationEpoch": 34567,
    "activationTimestamp": 1672531200,
    "exitEpoch": null,
    "withdrawableEpoch": null
  },
  "balance": {
    "actual": "32045123456789",
    "effective": "32000000000000"
  },
  "withdrawalCredentials": {
    "prefix": 1,
    "credential": "0x0100000000000000000000000a8c8aaa3f2ddf1b22a3f5b2a2e9b7d8c6f4e1a2",
    "address": "0x0a8c8aaa3f2ddf1b22a3f5b2a2e9b7d8c6f4e1a2"
  }
}

Validator Rewards

Paginated reward buckets aggregated by epoch, day, week, or month for a time range. Typical use case: pull daily rewards for a known validator pubkey for portfolio reporting (Lido, Beaver, etc.).
Data availability: Rewards are available from the Merge (epoch 146875, September 15, 2022) onward. If you need data going further back, contact us.

Endpoints

GET https://api.octav.fi/v1/beacon/validators/rewards/index/:index
GET https://api.octav.fi/v1/beacon/validators/rewards/pubkey/:pubkey

Query Parameters

rangeType
string
required
Determines how rangeFrom / rangeTo are interpreted.
  • timestamp — values are Unix seconds. Max range: 31,536,000 seconds (1 year).
  • epoch — values are beacon epoch numbers. Max range: 82,125 epochs (1 year).
rangeFrom
integer
required
Start of the range (inclusive). Must be ≥ 0 and ≤ rangeTo. Interpreted as Unix seconds or epoch number per rangeType.
rangeTo
integer
required
End of the range (inclusive). Must be ≥ 0. Interpreted as Unix seconds or epoch number per rangeType.
Maximum 1-year range. Cap is 31,536,000 seconds when rangeType=timestamp, 82,125 epochs when rangeType=epoch. For better performance, keep ranges as small as your use case allows.
granularity
string
required
Bucket size for aggregation. One of: epoch | day | week | month
offset
number
default:"0"
Pagination offset (number of records to skip).
limit
number
default:"10"
Number of records to return. Max 10.

Response

data
ValidatorRewardSummary[]
Array of reward buckets.
offset
number
Current pagination offset
limit
number
Records per page
totalRows
number
Total number of matching buckets
pages
number
Total number of pages

Example

curl "https://api.octav.fi/v1/beacon/validators/rewards/index/123456?rangeType=timestamp&rangeFrom=1704067200&rangeTo=1706745600&granularity=day&limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "data": [
    {
      "epochStart": 231200,
      "epochEnd": 231424,
      "timestampStart": 1704067200,
      "timestampEnd": 1704153600,
      "dateStart": "2024-01-01",
      "dateEnd": "2024-01-02",
      "consensusReward": "2450000000000",
      "consensusPotentialReward": "2500000000000",
      "consensusEfficiency": 0.98,
      "executionReward": "125000000000",
      "attestationsIncluded": 224,
      "attestationsMissed": 0,
      "syncParticipations": 0,
      "syncMissed": 0,
      "proposedBlocks": 0,
      "missedBlocks": 0,
      "mevBlocks": 0,
      "endEffectiveBalance": "32000000000000"
    }
  ],
  "offset": 0,
  "limit": 10,
  "totalRows": 31,
  "pages": 4
}

Validator Withdrawals

Paginated list of withdrawals processed for a validator.

Endpoints

GET https://api.octav.fi/v1/beacon/validators/withdrawals/index/:index
GET https://api.octav.fi/v1/beacon/validators/withdrawals/pubkey/:pubkey

Query Parameters

offset
number
default:"0"
Pagination offset.
limit
number
default:"10"
Number of records to return. Max 10.

Response

data
ValidatorWithdrawal[]
Array of withdrawal events.
offset
number
Current pagination offset
limit
number
Records per page
totalRows
number
Total number of withdrawals
pages
number
Total number of pages

Example

curl "https://api.octav.fi/v1/beacon/validators/withdrawals/index/123456?limit=10&offset=0" \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "data": [
    {
      "slot": 8901234,
      "epoch": 278163,
      "timestamp": 1706745600,
      "amount": "32000000000000",
      "address": "0x0a8c8aaa3f2ddf1b22a3f5b2a2e9b7d8c6f4e1a2",
      "index": 123456
    }
  ],
  "offset": 0,
  "limit": 10,
  "totalRows": 3,
  "pages": 1
}

Validator Deposits

Paginated list of deposits made to a validator.

Endpoints

GET https://api.octav.fi/v1/beacon/validators/deposits/index/:index
GET https://api.octav.fi/v1/beacon/validators/deposits/pubkey/:pubkey

Query Parameters

offset
number
default:"0"
Pagination offset.
limit
number
default:"10"
Number of records to return. Max 10.

Response

data
ValidatorDeposit[]
Array of deposit events.
offset
number
Current pagination offset
limit
number
Records per page
totalRows
number
Total number of deposits
pages
number
Total number of pages

Example

curl "https://api.octav.fi/v1/beacon/validators/deposits/pubkey/0xb03d97937ae39b38a44f90141dcf7f0420c3b9b21caee1a7603046bc9237f5c96b61714474249dafe0a20af583a4fc07?limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "data": [
    {
      "slot": 1234567,
      "epoch": 38579,
      "timestamp": 1634567890,
      "amount": "32000000000000000000",
      "depositIndex": 456789,
      "withdrawalCredentials": "0x0100000000000000000000000a8c8aaa3f2ddf1b22a3f5b2a2e9b7d8c6f4e1a2",
      "withdrawalAddress": "0x0a8c8aaa3f2ddf1b22a3f5b2a2e9b7d8c6f4e1a2"
    }
  ],
  "offset": 0,
  "limit": 10,
  "totalRows": 1,
  "pages": 1
}

Error Responses

Input validation failed (Joi structured error).
{ "error": "\"index\" must be a non-negative integer" }
Common causes: invalid :index or :pubkey format, missing required query params, rangeFrom > rangeTo, range exceeding 1-year cap, invalid rangeType or granularity value.
Missing or invalid Bearer token.
{ "message": "Unauthorized" }
Valid token but account does not have enterprise beacon access.
{ "error": "Beacon access requires enterprise subscription. Contact sales." }
Validator does not exist on mainnet.
{ "error": "Validator not found for index 99999999" }
Upstream beacon data error.
Error fetching validator details

Use Cases

Aggregate daily rewards across a set of validators and convert wei to ETH for portfolio reporting.
async function getDailyStakingYield(pubkeys, fromTs, toTs) {
  const buckets = {};

  for (const pubkey of pubkeys) {
    const params = new URLSearchParams({
      rangeType: 'timestamp',
      rangeFrom: String(fromTs),
      rangeTo: String(toTs),
      granularity: 'day',
      limit: '10'
    });

    const response = await fetch(
      `https://api.octav.fi/v1/beacon/validators/rewards/pubkey/${pubkey}?${params}`,
      { headers: { 'Authorization': `Bearer ${apiKey}` } }
    );
    const { data } = await response.json();

    data.forEach(b => {
      const total = BigInt(b.consensusReward) + BigInt(b.executionReward);
      buckets[b.dateStart] = (buckets[b.dateStart] ?? 0n) + total;
    });
  }

  return Object.entries(buckets).map(([date, wei]) => ({
    date,
    eth: Number(wei) / 1e18
  }));
}

Best Practices

validator.status, lifecycle.*, and withdrawalCredentials.* change on the order of minutes-to-hours, not seconds. Cache details responses for several minutes to cut latency and load.
const detailsCache = new Map(); // index -> { value, expiresAt }
const TTL_MS = 5 * 60 * 1000;

async function getValidatorDetails(index) {
  const cached = detailsCache.get(index);
  if (cached && cached.expiresAt > Date.now()) return cached.value;

  const response = await fetch(
    `https://api.octav.fi/v1/beacon/validators/details/index/${index}`,
    { headers: { 'Authorization': `Bearer ${apiKey}` } }
  );
  const value = await response.json();

  detailsCache.set(index, { value, expiresAt: Date.now() + TTL_MS });
  return value;
}
Reward buckets at granularity=epoch over a one-year range can yield ~82,000 rows. Match the granularity to the range so a single query returns a meaningful page.
RangeSuggested granularity
< 1 dayepoch
1–30 daysday
1–6 monthsweek
6 months – 1 yearmonth
Going finer than this still works, but you’ll need to paginate (limit is capped at 10) and stitch results together.
Reward and balance fields are returned as decimal strings in wei. Summing across long ranges or many validators can exceed Number.MAX_SAFE_INTEGER — parse with BigInt, divide by 10^18 only at the display step.
const totalWei = rewards.data.reduce(
  (sum, b) => sum + BigInt(b.consensusReward) + BigInt(b.executionReward),
  0n
);
const totalEth = Number(totalWei) / 1e18;
limit is capped at 10 for rewards, withdrawals, and deposits. Loop on offset until you’ve consumed totalRows.
async function fetchAll(url) {
  const all = [];
  let offset = 0;

  while (true) {
    const sep = url.includes('?') ? '&' : '?';
    const response = await fetch(
      `${url}${sep}limit=10&offset=${offset}`,
      { headers: { 'Authorization': `Bearer ${apiKey}` } }
    );
    const { data, totalRows } = await response.json();

    all.push(...data);
    offset += data.length;
    if (offset >= totalRows || data.length === 0) break;
  }

  return all;
}

Portfolio

Get full portfolio holdings for wallet addresses

Transactions

View on-chain transaction history