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

# Portfolio

> Use the Portfolio API to show account value, asset positions, transaction history, and historical portfolio performance.

## Overview

The Portfolio API gives you the account-level view after users deposit, withdraw, trade, or earn rewards. Use it to show current portfolio value, per-asset balances, an activity feed, and historical performance.

All Portfolio endpoints are scoped to a specific `account_id`. Pass the same `quote_symbol` across related calls when you want summary values, holdings, history, and transaction amounts to line up in the same currency.

## Prerequisites

* Payward Services API credentials (see the [Authentication guide](/tabs/developer-documentation/get-started/authentication))
* A verified user with at least one account
* Base URL: `https://api.services.payward.com`

## Portfolio workflow

Use this flow when you build a portfolio dashboard or reconcile user activity after payments and trades.

<Steps>
  <Step title="Show the account summary">
    Fetch total value, available value, withheld value, open-order value, and unrealized PnL.

    `GET /v1/accounts/{account_id}/portfolio/summary`
  </Step>

  <Step title="List asset positions">
    Fetch the asset-level balance breakdown for the portfolio.

    `GET /v1/accounts/{account_id}/portfolio/details`
  </Step>

  <Step title="Build the activity feed">
    Fetch transaction history for deposits, trades, price trigger swaps, and earn rewards.

    `GET /v1/accounts/{account_id}/portfolio/transactions`
  </Step>

  <Step title="Chart portfolio performance">
    Fetch historical balances and valuations for a selected time window.

    `GET /v1/accounts/{account_id}/portfolio/history`
  </Step>
</Steps>

## Step 1: show the account summary

Call `GET /v1/accounts/{account_id}/portfolio/summary` to get the top-level values for a portfolio dashboard.

<CodeGroup>
  ```python Python theme={null}
  def get_portfolio_summary(account_id, quote_symbol="USD", quote_type="fiat"):
      endpoint = f"/v1/accounts/{account_id}/portfolio/summary"
      params = {"quote_symbol": quote_symbol, "quote_type": quote_type}
      signature = get_payward_signature(endpoint, None, API_SECRET, params)

      headers = {
          "API-Key": API_KEY,
          "API-Sign": signature,
      }

      response = requests.get(
          f"{BASE_URL}{endpoint}",
          headers=headers,
          params=params,
      )
      return response.json()


  summary = get_portfolio_summary("ABCD1234EFGH5678")
  print(summary["data"]["value"])
  ```

  ```javascript Javascript theme={null}
  async function getPortfolioSummary(accountId, quoteSymbol = 'USD', quoteType = 'fiat') {
    const endpoint = `/v1/accounts/${accountId}/portfolio/summary`;
    const params = new URLSearchParams({ quote_symbol: quoteSymbol, quote_type: quoteType });
    const signature = getPaywardSignature(endpoint, null, API_SECRET, params);

    const response = await fetch(`${BASE_URL}${endpoint}?${params}`, {
      method: 'GET',
      headers: {
        'API-Key': API_KEY,
        'API-Sign': signature,
      },
    });

    return response.json();
  }

  const summary = await getPortfolioSummary('ABCD1234EFGH5678');
  console.log(summary.data.value);
  ```
</CodeGroup>

Use these fields for the dashboard header:

| Field            | How to use it                                                                                   |
| ---------------- | ----------------------------------------------------------------------------------------------- |
| `value`          | Total portfolio value in the requested `quote_symbol`.                                          |
| `cost_basis`     | Total cost basis of the portfolio, when available.                                              |
| `available`      | Value freely available for trading or withdrawal.                                               |
| `withheld`       | Value reserved across pending withdrawals, earn bonding or unbonding, and other platform holds. |
| `open_orders`    | Value held for open orders.                                                                     |
| `pnl.unrealized` | Unrealized profit and loss, when available.                                                     |

See the [Get Portfolio Summary API reference](/api-reference/portfolio/get-portfolio-summary) for the full response schema.

## Step 2: list asset positions

Call `GET /v1/accounts/{account_id}/portfolio/details` to show the user's holdings by asset.

<CodeGroup>
  ```python Python theme={null}
  def list_portfolio_details(account_id, quote_symbol="USD", quote_type="fiat"):
      endpoint = f"/v1/accounts/{account_id}/portfolio/details"
      params = {"quote_symbol": quote_symbol, "quote_type": quote_type}

      signature = get_payward_signature(endpoint, None, API_SECRET, params)
      headers = {
          "API-Key": API_KEY,
          "API-Sign": signature,
      }

      response = requests.get(
          f"{BASE_URL}{endpoint}",
          headers=headers,
          params=params,
      )
      return response.json()


  positions = list_portfolio_details("ABCD1234EFGH5678")
  for position in positions["data"]:
      print(position["symbol"], position["total"], position["total_in_quote"])
  ```

  ```javascript Javascript theme={null}
  async function listPortfolioDetails(accountId, quoteSymbol = 'USD', quoteType = 'fiat') {
    const endpoint = `/v1/accounts/${accountId}/portfolio/details`;
    const params = new URLSearchParams({ quote_symbol: quoteSymbol, quote_type: quoteType });

    const signature = getPaywardSignature(endpoint, null, API_SECRET, params);
    const response = await fetch(`${BASE_URL}${endpoint}?${params}`, {
      method: 'GET',
      headers: {
        'API-Key': API_KEY,
        'API-Sign': signature,
      },
    });

    return response.json();
  }

  const positions = await listPortfolioDetails('ABCD1234EFGH5678');
  for (const position of positions.data) {
    console.log(position.symbol, position.total, position.total_in_quote);
  }
  ```
</CodeGroup>

Use these fields for each position:

| Field                           | How to use it                                                      |
| ------------------------------- | ------------------------------------------------------------------ |
| `symbol`                        | Identify the held asset.                                           |
| `total`                         | Total balance in the asset itself.                                 |
| `total_in_quote`                | Total position value in the requested `quote_symbol`.              |
| `available`                     | Balance available after holds.                                     |
| `available_in_quote`            | Available balance value in the requested `quote_symbol`.           |
| `open_orders`                   | Asset amount held in open orders.                                  |
| `index_price`                   | Price used for current valuation in the response quote asset.      |
| `avg_entry_price_in_quote`      | Average acquisition price in the response quote asset, when known. |
| `cost_basis_in_quote`           | Cost basis in the response quote asset, when known.                |
| `pnl.unrealized`                | Unrealized PnL for the currently held lots.                        |
| `pnl.realized`                  | Total realized PnL for the asset.                                  |
| `pnl.reference_currency.symbol` | Currency symbol to use when displaying PnL amounts.                |
| `pnl.reference_currency.type`   | Asset type for the PnL reference currency.                         |
| `pnl.status.unrealized`         | Processing status for the unrealized PnL value.                    |
| `pnl.status.realized`           | Processing status for the realized PnL value.                      |

The `pnl` object is optional. `pnl.status` can appear without PnL amounts. `pnl.unrealized` and `pnl.realized` are returned only when the amount is available and PWS can expose its reference currency. When either amount is returned, `pnl.reference_currency` is returned with it. If a status field is `in_progress`, the corresponding PnL value is still being calculated and might be absent or not final. Use `pnl.reference_currency` when displaying PnL amounts instead of assuming that PnL always uses the requested `quote_symbol`.

See the [List Portfolio Details API reference](/api-reference/portfolio/list-portfolio-details) for all query parameters and response fields.

## Step 3: build the activity feed

Call `GET /v1/accounts/{account_id}/portfolio/transactions` to list user-visible portfolio activity. Use it after a deposit, withdrawal, swap, price trigger swap, or earn reward to show what changed and support reconciliation.

<CodeGroup>
  ```python Python theme={null}
  def list_portfolio_transactions(account_id, page_token=None):
      endpoint = f"/v1/accounts/{account_id}/portfolio/transactions"
      params = [
          ("types", "deposit"),
          ("types", "withdrawal"),
          ("types", "simple_order"),
          ("statuses", "successful"),
          ("start_timestamp", "2026-04-01T00:00:00Z"),
          ("end_timestamp", "2026-04-30T23:59:59Z"),
          ("sort_direction", "desc"),
          ("quote_symbol", "USD"),
          ("quote_type", "fiat"),
          ("page_size", "20"),
      ]
      if page_token:
          params.append(("page_token", page_token))

      signature = get_payward_signature(endpoint, None, API_SECRET, params)
      headers = {
          "API-Key": API_KEY,
          "API-Sign": signature,
      }

      response = requests.get(
          f"{BASE_URL}{endpoint}",
          headers=headers,
          params=params,
      )
      return response.json()


  transactions = list_portfolio_transactions("ABCD1234EFGH5678")
  for transaction in transactions["data"]:
      print(transaction["timestamp"], transaction["type"], transaction.get("status"))
  ```

  ```javascript Javascript theme={null}
  async function listPortfolioTransactions(accountId, pageToken = null) {
    const endpoint = `/v1/accounts/${accountId}/portfolio/transactions`;
    const params = new URLSearchParams();
    params.append('types', 'deposit');
    params.append('types', 'withdrawal');
    params.append('types', 'simple_order');
    params.append('statuses', 'successful');
    params.set('start_timestamp', '2026-04-01T00:00:00Z');
    params.set('end_timestamp', '2026-04-30T23:59:59Z');
    params.set('sort_direction', 'desc');
    params.set('quote_symbol', 'USD');
    params.set('quote_type', 'fiat');
    params.set('page_size', '20');
    if (pageToken) params.set('page_token', pageToken);

    const signature = getPaywardSignature(endpoint, null, API_SECRET, params);
    const response = await fetch(`${BASE_URL}${endpoint}?${params}`, {
      method: 'GET',
      headers: {
        'API-Key': API_KEY,
        'API-Sign': signature,
      },
    });

    return response.json();
  }

  const transactions = await listPortfolioTransactions('ABCD1234EFGH5678');
  for (const transaction of transactions.data) {
    console.log(transaction.timestamp, transaction.type, transaction.status);
  }
  ```
</CodeGroup>

Common filters:

| Filter                                | How to use it                                                                                                                                  |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `types`                               | Filter by `simple_order`, `simple_order_failed`, `price_trigger_swap`, `price_trigger_swap_failed`, `earn_reward`, `deposit`, or `withdrawal`. |
| `statuses`                            | Filter by `in_progress`, `successful`, `failed`, `no_status`, or `uncategorized`.                                                              |
| `start_timestamp` and `end_timestamp` | Restrict results to a time window.                                                                                                             |
| `assets`                              | Filter by asset references using indexed deep-object syntax.                                                                                   |
| `ids`                                 | Look up specific portfolio transaction IDs.                                                                                                    |
| `sort_direction`                      | Return newest-first with `desc` or oldest-first with `asc`.                                                                                    |
| `quote_symbol`                        | Add best-effort `amount_in_quote` values to spend, receive, and fee amounts. Defaults to `USD`.                                                |
| `quote_type`                          | Use `fiat`. Other quote types are not currently supported.                                                                                     |

Each transaction can include `spend`, `receive`, or both. Failed transactions can omit movement details, so build your UI around the required fields `id`, `timestamp`, and `type`, then display optional money movement fields when present.

Use `next_page_token` as `page_token` to fetch more transactions.

See the [List Portfolio Transactions API reference](/api-reference/portfolio/list-portfolio-transactions) for all filters and response fields.

## Step 4: chart portfolio performance

Call `GET /v1/accounts/{account_id}/portfolio/history` to draw a portfolio value chart or show how balances changed over time.

<CodeGroup>
  ```python Python theme={null}
  def list_portfolio_history(account_id):
      endpoint = f"/v1/accounts/{account_id}/portfolio/history"
      params = [
          ("start_timestamp", "2026-04-01T00:00:00Z"),
          ("end_timestamp", "2026-04-30T23:59:59Z"),
          ("quote_symbol", "USD"),
          ("quote_type", "fiat"),
          ("assets[0][symbol]", "BTC"),
          ("assets[0][type]", "crypto"),
          ("assets[1][symbol]", "ETH"),
          ("assets[1][type]", "crypto"),
      ]

      signature = get_payward_signature(endpoint, None, API_SECRET, params)
      headers = {
          "API-Key": API_KEY,
          "API-Sign": signature,
      }

      response = requests.get(
          f"{BASE_URL}{endpoint}",
          headers=headers,
          params=params,
      )
      return response.json()


  history = list_portfolio_history("ABCD1234EFGH5678")
  for point in history["data"]:
      print(point["timestamp"], point.get("value"))
  ```

  ```javascript Javascript theme={null}
  async function listPortfolioHistory(accountId) {
    const endpoint = `/v1/accounts/${accountId}/portfolio/history`;
    const params = new URLSearchParams();
    params.set('start_timestamp', '2026-04-01T00:00:00Z');
    params.set('end_timestamp', '2026-04-30T23:59:59Z');
    params.set('quote_symbol', 'USD');
    params.set('quote_type', 'fiat');
    params.set('assets[0][symbol]', 'BTC');
    params.set('assets[0][type]', 'crypto');
    params.set('assets[1][symbol]', 'ETH');
    params.set('assets[1][type]', 'crypto');

    const signature = getPaywardSignature(endpoint, null, API_SECRET, params);
    const response = await fetch(`${BASE_URL}${endpoint}?${params}`, {
      method: 'GET',
      headers: {
        'API-Key': API_KEY,
        'API-Sign': signature,
      },
    });

    return response.json();
  }

  const history = await listPortfolioHistory('ABCD1234EFGH5678');
  for (const point of history.data) {
    console.log(point.timestamp, point.value);
  }
  ```
</CodeGroup>

Use the history endpoint for:

* Portfolio value charts with `timestamp` and `value`.
* Historical PnL views with `total_pnl`, when available.
* Historical asset-balance charts when you request `assets` filters with both `symbol` and `type`.
* Quote-aware charts with top-level `quote_symbol`, `quote_type`, `start_timestamp`, and `end_timestamp`.

The history endpoint returns a maximum of 365 data points per request. Use a narrower time window when you need fewer points.

<Note>
  A missing asset balance at the start of the range means the user did not hold that asset at that time. A zero balance
  means the user may have held the asset previously, but did not hold it at that snapshot. The latest daily balance can
  be delayed by up to about five hours after UTC midnight while data is processed.
</Note>

See the [List Portfolio History API reference](/api-reference/portfolio/list-portfolio-history) for all query parameters and response fields.

## API reference

| Endpoint                                           | Method | Description                                                                            |
| -------------------------------------------------- | ------ | -------------------------------------------------------------------------------------- |
| `/v1/accounts/{account_id}/portfolio/summary`      | GET    | Get total portfolio value, availability, holds, and unrealized PnL                     |
| `/v1/accounts/{account_id}/portfolio/details`      | GET    | List asset-level balances, valuation, open orders, cost basis, and PnL                 |
| `/v1/accounts/{account_id}/portfolio/transactions` | GET    | List portfolio transactions for deposits, swaps, price trigger swaps, and earn rewards |
| `/v1/accounts/{account_id}/portfolio/history`      | GET    | List historical balances and valuations for a portfolio                                |
