---
title: "Get portfolio"
method: POST
path: "/v1/tools/betteroff_get_portfolio"
tags: ["tools"]
---

# Get portfolio

`POST /v1/tools/betteroff_get_portfolio`

## Request

- Base URL: `https://api.betteroff.finance`
- URL: `https://api.betteroff.finance/v1/tools/betteroff_get_portfolio`
- Auth: one of:
  - OpenID Connect (`https://app.betteroff.finance/api/auth/.well-known/openid-configuration`, scopes: `investments:read`)
  - HTTP bearer

Use this when the user asks about investment holdings, allocation, or concentration. Read portfolio positions, allocation, and concentration for the full filtered portfolio. includePositions false returns the allocation summary; true pages positions by cursor.

## Request body

- object
  - `symbol` string, nullable, required: Filter by ticker symbol (e.g. AAPL, BTC, ETH). Use null for all symbols.
  - `instrumentId` string, nullable, required: Filter by canonical instrument ID. Preferred over symbol when available. Use null for all.
  - `type` string, nullable, required: Filter by holding type (equity, etf, mutual_fund, crypto). Use null for all types.
  - `groupBy` 'type' | 'account' | 'symbol' | 'instrument' | 'underlying', required: Group by type, account, symbol, separate instrument, or underlying ISIN exposure across brokerage holdings and Stock Tokens.
  - `includePositions` boolean, required
  - `cursor` object, nullable
    - `offset` integer, required
    - `revision` integer, required
  - `limit` integer, nullable, required

## Response `200`

Tool result

- union
  - object
    - `ok` false, required
    - `requestId` string
    - `error` string, required
    - `code` string, required
    - `retryable` boolean, required
    - `nextStep` string, required
    - `field` string
    - `missingInputs` object[]
      - `id` string, required
      - `name` string, required
      - `balanceMissing` boolean, required
      - `interestRateMissing` boolean, required
      - `minimumPaymentMissing` boolean, required
  - object
    - `ok` true, required
    - `requestId` string
    - `schemaVersion` '4', required
    - `data` object, required
      - `baseCurrency` string, required
      - `holdingCount` integer, required
      - `positions` object[], required
        - `accountId` string, nullable, required
        - `chain` string, nullable, required
        - `stockToken` object, nullable, required
        - `valuationKnown` boolean, required
        - `priceKnown` boolean, required
        - `instrumentId` string, nullable, required
        - `symbol` string, nullable, required
        - `name` string, nullable, required
        - `type` string, nullable, required
        - `quantity` number, required
        - `price` string, required: Decimal text, e.g. "-12.50". Read the currency beside it or on the result.
        - `value` string, required: Decimal text, e.g. "-12.50". Read the currency beside it or on the result.
        - `currency` string, nullable, required
        - `basisSource` string, nullable, required
        - `returnPct` number, nullable, required
        - `isManual` boolean, required
        - `account` string, nullable, required
      - `coverage` object, required
      - `analysis` object, required
      - `conversionIncomplete` boolean, required
      - `page` object, required
    - `currency` string, nullable, required
    - `timezone` string, required
    - `asOf` string, nullable, required
    - `revision` integer, required
    - `householdRevision` integer, required
    - `quality` object, required
      - `state` 'complete' | 'partial' | 'unavailable', required
      - `reasons` string[], required
    - `evidence` object[], required
      - `source` string, required
      - `id` string
      - `observedAt` string, nullable, required
    - `page` object, required
      - `returnedCount` integer, required
      - `totalCount` integer, nullable, required
      - `truncated` boolean, required
      - `nextCursor` Schema4, required (unresolved $ref)
    - `warnings` string[], required
    - `notes` string

## Other responses

- `400`: INVALID_INPUT (a missing, unknown, or invalid argument, named in `fields`), TOOL_CALL_REJECTED, or a body that is not JSON.
- `401`: AGENT_TOKEN_INVALID: the token is missing, expired, or revoked.
- `402`: AGENT_SUBSCRIPTION_INACTIVE or FEATURE_NOT_INCLUDED: needs BetterOff Core.
- `403`: INSUFFICIENT_SCOPE, ACCESS_DENIED, or AGENT_GRANT_REVOKED.
- `404`: TOOL_NOT_FOUND, or NOT_FOUND for a record the org does not have.
- `409`: CONFLICT: the record's state rules this call out. Read it again.
- `422`: INCOMPLETE_DATA or RESULT_TOO_LARGE. Narrow the request; don't retry as is.
- `429`: RATE_LIMITED. Retry after Retry-After seconds.
- `503`: DATA_UNAVAILABLE, DEPENDENCY_UNAVAILABLE (including the 25-second tool deadline), or AGENT_AUTHZ_UNAVAILABLE. Retryable.
- `default`: Problem details

---

[API](https://skmtc.dev/betteroff/apis/betteroff-api.md) · [All operations](https://skmtc.dev/betteroff/apis/betteroff-api/llms.txt) · [OpenAPI document](https://skmtc.dev/betteroff/apis/betteroff-api/revisions/bc858c8d428d?raw)
