# TypeScript SDK — Account Services: Staking

Stake and unstake crypto, view staking balances, rates, rewards, and event history. All methods are on `client.accountServices`.

See the [API specifications](/api-specifications) for full request/response schemas and the [authentication guide](/tools/typescript-sdk/authentication) for setup.

## Methods

### listStakingBalances

`POST /v1/balances/staking` · Authenticated

Returns staking balances for all staked assets in the account. The response is a bare array of `StakingBalance` objects.

```ts
const balances = await client.accountServices.listStakingBalances({});

for (const entry of balances) {
  // balance, available, and availableForWithdrawal are numbers
  console.log(`${entry.currency}: ${entry.balance} staked`);
}
```

> **Tip:** `balance`, `available`, and `availableForWithdrawal` are **numbers** (not strings). The `balanceByProvider` field is an object keyed by provider UUID.

### listStakingRates

`GET /v1/staking/rates` · Public

Returns current staking rates for all supported assets. This is the **only public GET** in the account services namespace — it requires no authentication and takes no arguments.

The response is a **nested object** keyed by provider UUID, then by currency symbol — not a flat array.

```ts
// No auth needed — works with an unauthenticated client
const rates = await client.accountServices.listStakingRates();

// rates is keyed by provider UUID, then by currency
for (const [providerId, currencies] of Object.entries(rates)) {
  for (const [currency, rate] of Object.entries(currencies as Record<string, any>)) {
    console.log(`${currency}: ${rate.ratePct}% (provider: ${providerId})`);
  }
}
```

> **Tip:** As a GET operation, this is automatically retried on transient errors (429, 502, 503, 504). All other account services methods are POST mutations that are never retried.

### listStakingRewards

`POST /v1/staking/rewards` · Authenticated

Returns staking reward history for the account. The response is a **nested object** keyed by provider UUID, then by currency symbol — the same nested structure as `listStakingRates`.

```ts
const rewards = await client.accountServices.listStakingRewards({
  since: "2024-01-01T00:00:00.000Z",
});

// rewards is keyed by provider UUID, then by currency
for (const [providerId, currencies] of Object.entries(rewards)) {
  for (const [currency, reward] of Object.entries(currencies as Record<string, any>)) {
    console.log(`${currency}: ${reward.accrualTotal} earned (provider: ${providerId})`);
  }
}
```

This is a POST mutation — never automatically retried.

### listStakingEventHistory

`POST /v1/staking/history` · Authenticated

Returns a chronological history of staking events (stakes, unstakes, rewards). The default sort order is **newest first**. The request body accepts optional `since` and `until` fields (bigint or number) for time-range filtering. The response is an array of `StakingHistory` objects, each containing a `providerId` and a `transactions` array.

```ts
const history = await client.accountServices.listStakingEventHistory({
  since: 1700000000000,
});

for (const provider of history) {
  console.log(`Provider: ${provider.providerId}`);
  for (const tx of provider.transactions ?? []) {
    console.log(`  ${tx.transactionType}: ${tx.amount} ${tx.amountCurrency}`);
  }
}
```

> **Tip:** `since` and `until` accept bigint or number values for timestamp-based pagination. Each `StakingTransaction` has `transactionType` (e.g. `"Deposit"`, `"Redeem"`, `"Interest"`), `amount` (number), and `amountCurrency`.

### stakeCryptoFunds

`POST /v1/staking/stake` · Authenticated

Stakes cryptocurrency with a staking provider. The request body is [validated client-side](/tools/typescript-sdk/deep-dives/request-validation). The SDK enforces:

- `providerId` — required string
- `currency` — required string
- `amount` — required decimal string

```ts
const result = await client.accountServices.stakeCryptoFunds({
  providerId: "62b21e17-2534-4b9f-afcf-b7edb609dd8d",
  currency: "ETH",
  amount: "10.0",
});

console.log(result.transactionId); // unique staking transaction ID
```

This is a POST mutation — never automatically retried. Staking may have lock-up periods depending on the provider and asset. Amounts must be quoted decimal strings (e.g. `"10.0"`, not `10`).

### unstakeCryptoFunds

`POST /v1/staking/unstake` · Authenticated

Initiates an unstaking request. The request body is [validated client-side](/tools/typescript-sdk/deep-dives/request-validation) with the same rules as `stakeCryptoFunds`:

- `providerId` — required string
- `currency` — required string
- `amount` — required decimal string

```ts
const result = await client.accountServices.unstakeCryptoFunds({
  providerId: "62b21e17-2534-4b9f-afcf-b7edb609dd8d",
  currency: "ETH",
  amount: "5.0",
});

console.log(result.transactionId); // unique unstaking transaction ID
```

This is a POST mutation — never automatically retried. Unstaking may be subject to a cooldown period before funds become available.

## What's next

- [Balances & Account](/tools/typescript-sdk/reference/account-services/balances-and-account) — check available and staking balances
- [Data Types](/tools/typescript-sdk/deep-dives/data-types) — decimal strings and bigint fields
- [Request Validation](/tools/typescript-sdk/deep-dives/request-validation) — how client-side validation works
