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

# Building staking reporting

> Construct staking reporting on APIv2, and identify which parts APIv3 replaces and which reporting is new.

Staking reporting draws on different endpoints from staking itself, and the two API versions do not describe a position the same way. This page covers how to build a complete report on APIv2, which parts of it APIv3 replaces, and which reporting exists only on APIv3.

APIv3 staking reads are available to clients staking SOL, or ETH on `0x02` validators, and require APIv3 staking to be enabled for your organization. Every APIv2 and APIv3 endpoint on this page needs the **Read vault activity** permission on the vaults you report on. For how to grant it, see [Permission groups](/knowledge-base/platform/developers/permission-groups).

## The APIv2 reporting surface

Four endpoints carry everything APIv2 reports about staking.

| Endpoint | What it reports |
| :- | :- |
| `GET /v2/wallets/{walletId}/staking/positions` | One row per position, with staked and inactive amounts |
| `GET /v2/wallets/{walletId}/staking/rewards` | Reward amounts split into claimed and unclaimed, by date |
| `GET /v2/wallets/{walletId}` | Wallet balances per asset, including USD valuation |
| `GET /v2/vaults/{vaultId}` | The same asset rollup at vault level |

A position row carries `stakingPositionId`, `assetType`, `stakedAmount`, `inactiveStakedAmount`, `status`, `providerName`, `sourceAddress`, `withdrawalAddress`, and `transactionId`. Position `status` is one of `PENDING`, `ACTIVE`, or `EXITED`. Wallet and vault asset details carry `availableBalance`, `stakedBalance`, `totalBalance`, `unclaimedBalance`, `unvestedBalance`, and `unvestedUnstakeableBalance`, each as an amount with `quantity`, `currentPrice`, and `currentUSDValue`.

## Constructing a position report on APIv2

<Steps>
  <Step title="List positions for each wallet">
    Call `GET /v2/wallets/{walletId}/staking/positions` and follow `page.next` until it returns null.
  </Step>

  <Step title="Read staked and inactive amounts per position">
    Take `stakedAmount` and `inactiveStakedAmount` from each row, and group by `assetType`.
  </Step>

  <Step title="Read the wallet rollup">
    Read `stakedBalance` from `GET /v2/wallets/{walletId}`, which also supplies USD valuation. `stakedBalance` sums several underlying balances, so it need not equal your per-position total.
  </Step>

  <Step title="Attach rewards">
    Call `GET /v2/wallets/{walletId}/staking/rewards` and split by `rewardType`, which is `CLAIMED` or `UNCLAIMED`, using `referenceDate` for the period.
  </Step>
</Steps>

## The pending and exiting stake gap on APIv2

APIv2 does not return non-zero values for pending or exiting stake. A position appears with `status` set to `PENDING` while its deposit is confirmed but not yet active, and during that window its amount is not reported anywhere on APIv2.

The documented workaround was to recover the amount from the transaction that created the position:

1. Call `GET /v2/wallets/{walletId}/staking/positions` and filter to rows where `status` is `PENDING`.
2. For each row, take its `transactionId` and call `GET /v2/transactions/{transactionId}` to read that transaction's `amount`.
3. Sum those amounts by asset type, and treat the total as the pending stake missing from `stakedBalance`.

This does not work in practice. Staking transactions return `amount.quantity` as `"0"` on `GET /v2/transactions/{transactionId}`, so step 2 recovers nothing. They also carry `transactionType` `"OTHER"`, because APIv2 reserves its specific types for deposits, withdrawals, and transfers. Identify a staking transaction by the position's `transactionId` rather than by its type. The position's `status` also stays `PENDING` after the transaction itself reads `SUCCESS`, so a reporting job that runs shortly after a stake request sees a pending position whose amount is unavailable from either endpoint.

<Warning>
  If your reporting reads `stakedBalance` alone, stake that is activating or exiting is absent from the figure, and there is no APIv2 endpoint that recovers it. Report pending and exiting stake from APIv3 instead.
</Warning>

## What APIv3 replaces

APIv3 reports staking balances as typed buckets rather than two amount fields plus a status. Per-position balances come from `GET /v3/wallets/{walletId}/staking-positions/{positionId}/balances`, and wallet-level figures for the same buckets come from `GET /v3/wallets/{walletId}/balances`.

Each row below is the nearest equivalent, not a rename. The two versions build these amounts from different underlying balances, so a figure can change when you switch versions even where the concept matches.

| Reporting need | APIv2 | Nearest APIv3 equivalent |
| :- | :- | :- |
| Activating stake, as an amount | Not available | `ACTIVATING_STAKE` |
| Deactivating stake, as an amount | Not available | `DEACTIVATING_STAKE` |
| Inactive stake, per position | `inactiveStakedAmount` | `INACTIVE_STAKE` |
| Active stake, per position | `stakedAmount` | `ACTIVE_STAKE` |
| Wallet staked total | `stakedBalance` | `ACTIVE_STAKE`, but narrower |
| Wallet available balance | `availableBalance` | `AVAILABLE` |
| Wallet total balance | `totalBalance` | `TOTAL`, not an identity over the buckets |
| Position lifecycle | `status` | Derived from which buckets are non-zero |

Field names and pagination also differ. An APIv2 amount names its value `quantity`, while an APIv3 amount names it `amount`. APIv2 paginates with `page.next`, while APIv3 uses `page.endCursor` fed into an `after` parameter, with a `first` page size of 25 by default and 100 at most.

### `ACTIVE_STAKE` is narrower than `stakedBalance`

<Warning>
  On Ethereum, `stakedBalance` sums five underlying balances and `ACTIVE_STAKE` carries one. Switching a report from one to the other can drop stake with nothing in the response to signal it.
</Warning>

The stake `ACTIVE_STAKE` leaves out on Ethereum includes restaked positions, stake restaked in the beacon chain, Alluvial staking, and delegated stake that remains usable. So an organization holding EigenLayer or Alluvial positions sees an `ACTIVE_STAKE` lower than its `stakedBalance`.

Adding the four APIv3 staking buckets together does not recover `stakedBalance` either. `ACTIVATING_STAKE` and `DEACTIVATING_STAKE` cover stake that `stakedBalance` never included, so the two sets overlap on the principal and diverge in both directions.

On assets that report claimable rewards as a position state, `ACTIVE_STAKE` folds those rewards in as well, where APIv2 reports them separately as `unclaimedBalance`.

Each asset defines its own composition, and there is no shared definition holding the two versions in step, so confirm the make-up of a figure for every asset you report on rather than generalizing from Ethereum.

### Absent buckets mean zero

A balance type missing from an APIv3 response means zero, not unknown, so summing is safe on both endpoints. A report that treats an absent bucket as unreported will mis-total.

The two endpoints differ in whether a zero appears at all. `GET /v3/wallets/{walletId}/balances` drops zero-valued entries, so a wallet with no activating stake has no `ACTIVATING_STAKE` row. The per-position endpoint applies no such filter and emits what the position reports, zeros included. So on a position, an explicit zero is meaningful while absence is not, and you cannot read "this position has no active stake" from a missing `ACTIVE_STAKE` entry.

## Wallet balances and staking positions answer different questions

The two APIv3 balance endpoints read from different sources by design, so the numbers they return can differ.

`GET /v3/wallets/{walletId}/balances` reads the wallet's named balances. It does not consult validators, so staked balance is counted whatever created it.

`GET /v3/wallets/{walletId}/staking-positions` asks the Ethereum module for the validators it manages, and that lookup covers `0x02` validators only. This is deliberate. A wallet holding only `0x01` validators stays on the legacy Ethereum staking flow, and standardized staking applies to wallets that hold at least one `0x02` validator.

On a wallet that holds `0x01` validators, that stake is included in the wallet's `ACTIVE_STAKE` and has no row in the position list. Both endpoints return what they are designed to return.

On such a wallet, the wallet figure and the sum of the per-position figures are not expected to agree. The difference is the `0x01` stake, and it reflects a difference in scope, not a shortfall.

APIv2 presented these as positions by synthesizing one from the validator record. APIv3 reports the validators the staking flow manages, so if you are moving a report across and relied on those synthesized rows, expect a shorter position list for the same wallet.

### Bringing legacy validators into position-level reporting

If you want stake currently held by `0x01` validators to appear in the APIv3 position list, consolidate those validators into a `0x02` validator. The stake then reports as an ordinary APIv3 staking position, and the wallet figure and the summed position figures line up again.

Consolidation runs on APIv2 through `POST /v2/transactions/consolidate-stake`. See [Pre-Pectra staking](/knowledge-base/platform/developers/staking/eth-staking), under "Consolidate Stake from Pre-Pectra to Pectra", and [Pectra staking](/knowledge-base/platform/developers/staking/eth-pectra-staking), under "Consolidate to Pectra validator". You can consolidate from a non-Pectra validator into a Pectra validator, across wallets and vaults, but not into a non-Pectra validator and not across staking providers.

<Warning>
  Consolidation is irreversible. Anchorage Digital performs it on request, so agree the scope before it runs. See [Staking ETH](/knowledge-base/platform/users/staking/eth) for how consolidation is handled for your organization.
</Warning>

### Organization enablement

APIv3 staking is enabled per organization. A wallet whose organization does not have it enabled returns an error from `GET /v3/wallets/{walletId}/staking-positions` rather than an empty list, so handle an error and an empty list as different outcomes. If you see the error, contact your client experience team to confirm enablement.

## What APIv3 adds

These have no APIv2 equivalent.

* `ACTIVATING_STAKE` and `DEACTIVATING_STAKE` report activating and exiting stake as amounts, per position and at wallet level. They close the APIv2 gap described above.
* `GET /v3/wallets/{walletId}/balances` returns all four staking buckets for a wallet in one call, so a wallet report does not need a call per position.
* `HELD` covers holds on the wallet's primary address, such as pending withdrawals and settlements.
* `GET /v3/wallets/{walletId}/rewards` returns individual reward events over a date range. Each event carries `stakingPositionId` and `transactionHash` where applicable, so a reward can be attributed to a validator or stake account.
* `GET /v3/wallets/{walletId}/daily-rewards` returns one row per day per reward type, over a range of up to 31 days.
* Both reward endpoints classify rewards by source rather than by claim state.
* A Solana position reports `stakeAuthority`, `withdrawAuthority`, and `validatorVoteAccount`, which identifies positions delegated through a third-party staking product.

## Querying rewards on APIv3

The two reward endpoints take their reward type differently, and accept different values.

| | Per-event `/rewards` | Daily `/daily-rewards` |
| :- | :- | :- |
| Parameter | `rewardType`, a single value | `rewardTypes`, an array of at least one |
| Date range | `startDate` and `endDate` | `startDate` and `endDate`, up to 31 days |
| Accepts `CONSENSUS_LAYER_REWARDS` | No | Yes |

Both accept `DELEGATION_REWARDS`, `DELEGATION_MEV_REWARDS`, `EXECUTION_LAYER_REWARDS`, `BLOCK_PROPOSER_REWARDS`, `ATTESTATION_REWARDS`, and `SYNC_COMMITTEE_REWARDS`. The daily endpoint also accepts `CONSENSUS_LAYER_REWARDS`, which is an aggregate of `BLOCK_PROPOSER_REWARDS`, `ATTESTATION_REWARDS`, and `SYNC_COMMITTEE_REWARDS`.

<Warning>
  Do not query an aggregate type and any of its component types in the same `rewardTypes` array. The components are already counted inside the aggregate, so the response double-counts them, and the API does not reject the combination. This applies to the daily endpoint only, since the per-event endpoint takes a single type and does not accept the aggregate.
</Warning>

## What stays on APIv2

A complete report still calls APIv2 for the following.

* `currentPrice` and `currentUSDValue` exist on APIv2 only. An APIv3 amount carries only `amount` and `assetType`, so USD valuation comes from APIv2.
* APIv2 `rewardType` reports whether a reward is claimed. APIv3 reward types report where a reward came from, so one does not substitute for the other.
* `unclaimedBalance`, `unvestedBalance`, and `unvestedUnstakeableBalance` have no APIv3 equivalent today.
* `GET /v2/vaults/{vaultId}` reports vault-level rollups with `vaultId` and `vaultName`.
* `GET /v2/transactions/{transactionId}` reports a transaction's status, one of `INITIATING`, `NEEDS_APPROVAL`, `INPROGRESS`, `SUCCESS`, `REJECTED`, `EXPIRED`, and `FAILURE`, and its `blockchainTxId`, the on-chain hash. The APIv3 read endpoints on this page report neither.
* An APIv2 position carries the `transactionId` of the operation that created it, and the positions endpoint accepts it as a filter. The filter applies on ETH but not on SOL. See [Getting started with staking API](/knowledge-base/platform/developers/staking/staking-overview) for the polling pattern.

Because APIv3 currently exposes neither claim state nor an unclaimed balance, APIv2 is the only source for outstanding rewards on assets whose rewards must be claimed.

## A mixed reporting pattern

Both versions report on the same wallets and staking positions, so one report can take each figure from whichever version reports it best.

| Report element | Source |
| :- | :- |
| Stake by state, including activating and exiting | APIv3 staking position and wallet balances |
| USD valuation of those balances | APIv2 wallet or vault asset details |
| Reward attribution by position and date | APIv3 rewards or daily rewards |
| Claimed against unclaimed rewards | APIv2 staking rewards |
| Operation outcome, including rejection and expiry | APIv2 transaction status |
| On-chain confirmation | APIv2 `blockchainTxId`, checked against a node or explorer |

<Note>
  `SUCCESS` on `GET /v2/transactions/{transactionId}` describes the transaction, not on-chain finality. Check `blockchainTxId` against your own node or a block explorer to confirm inclusion and depth before treating a position as settled in a report.
</Note>


## Related topics

- [Operation tagging](/knowledge-base/platform/users/web-dashboard/operation-tagging.md)
- [Reporting](/knowledge-base/platform/users/web-dashboard/reporting.md)
- [BNB staking](/knowledge-base/platform/users/staking/bnb.md)
- [Staking overview](/knowledge-base/platform/users/staking/overview.md)
- [Home](/knowledge-base/index.md)
