Holdings
Holdings are daily positions — what a lens held, per date, valued in one reporting currency. By default the endpoint returns one fully aggregated row per date in the lens client's primary currency; currency reads another of the client's currencies, and the expand parameter breaks the aggregation down by asset, custody account, cash account or tag. This is the heaviest read endpoint on the platform, so scope your date ranges deliberately.
Data model
Each row is one cell of the (date × expansion) grid.
Every holding is kept once per reporting currency of its client: the same position valued in DKK, in EUR and in USD is three legs, as in the legacy platform. A read returns one leg, the currency you ask for. The client's currencies are its primary currency, its entities' primary currencies and their alternative currencies; any other currency is a 400 that lists them.
A holding sits on one custody account or one cash account, or on neither (a private-market or loan position). A portfolio that sits in more than one of the lens's portfolio groups counts once per group, as in the legacy API: a row across accounts includes it once for each group. Split by both accounts (expand=custody_accounts,cash_accounts), each account is one row with its own value.
A lens built in v1 is read through its rules. Each row counts with the lens's weight of it: in full when the lens takes its portfolio, custody or cash account, custodian, asset or tag whole, and with the share when it takes a party, an entity or an ownership path that owns part of the portfolio on the row's date. A lens rule never adds to what you can see: a row counts with the smaller of the lens's weight and your own share. Such a lens counts each row once, also when it sits under several sub-lenses. Before the lens's start_date it shows nothing: a read that ends before it is an empty list, and a window that starts before it starts on it. A lens synced from the legacy platform keeps its legacy portfolio groups.
Numbers follow your ownership. If you see a portfolio only as its owner (an access grant on a party), units and market_value are your share of it on each date: an owner of 40 % sees 40 %. The share changes on the dates the ownership changes. A portfolio you also see through any other access point (the tenant, a client, an entity, a cash or custody account) counts in full, and so does everything an admin reads. Which portfolios you see follows your access today, and an owner grant reaches the entities the party owns directly; the share is the one on each row's date, so a date before the ownership began has no row. The v2 and v3 holdings routes are not weighted.
idstring or null{account_id}:{asset_id}:{date}:{currency_code}, the idGET /v1/holdings/{id}takes, whereaccount_idis the custody or cash account the holding sits on. Set only when the row is exactly one holding:expandincludesassets,custody_accountsandcash_accounts, and the holding sits on an account.nullotherwise.dateISO 8601 dateThe day of the position. The envelope's
as_ofis the last day the read covers, so on a window it is thedateof the last rows.asset_idstring or nullSet when
expandincludesassets;nullwhen the row aggregates across assets.custody_account_idstring or nullThe custody account id, set when
expandincludescustody_accounts;nullwhen the row aggregates across custody accounts, and on positions held outside a custody account.cash_account_idstring or nullThe cash account id, set when
expandincludescash_accounts;nullwhen the row aggregates across cash accounts, and on positions held outside a cash account. A cash-account position sits on its cash account; every other position on its custody account.tag_idstring or nullThe asset's classification as a tag, set when
expandincludestags;nullwhen the row aggregates across tags, and on a classification without a tag.currency_codestringISO 4217 currency the row is valued in: the
currencyof the read.unitsdecimal string or nullQuantity held. Set only when
expandincludesassets;nullon rows across assets, where a sum of units means nothing.market_valuedecimal stringMarket value of the position. Serialized as a string — parse with a decimal type, never a float.
List holdings
Returns positions for a lens on one day or over a date window, in the standard v1 list envelope. An unknown query parameter is a 400. as_of reads one day and from_date with to_date reads a window; with no date the read is today. as_of together with a window, only one of from_date and to_date, or a to_date before from_date, is a 400. The envelope's as_of is the day the read ends on. Positions on a deleted cash or custody account are left out, as those accounts are, and so are the portfolios the legacy platform deleted or that moved away, as the legacy platform hides them. Scope positions:read.
Query parameters
lens_idstringThe lens to read positions for. Required.
as_ofISO 8601 dateThe day to read. Today when left out; not together with
from_dateandto_date.from_dateISO 8601 dateInclusive start of the window. Only together with
to_date.to_dateISO 8601 dateInclusive end of the window. Only together with
from_date.currencystringThe reporting currency to read, one of the lens client's currencies. The client's primary currency when left out; any other is a
400listing the valid ones. A read that is empty before the check, because the window ends before the lens'sstart_dateor the lens has no portfolio you can see, answers the empty list without checkingcurrency.expandstringComma-separated dimensions to break the aggregation down by:
assets,custody_accounts,cash_accounts,tags. Any other token is a400. Omit for one aggregated row per date.limitintegerPage size. Defaults to 1 000, capped at 10 000.
cursorstringOpaque cursor from the previous page's
next_cursor. Omit for the first page.
curl -G https://api.aleta.ai/v1/holdings \
-H "Authorization: Bearer {access_token}" \
-d lens_id=019f91be-1d83-7f0a-bbfc-e64861142e87 \
-d from_date=2025-01-30 \
-d to_date=2025-02-28
{
"data": [
{
"id": null,
"date": "2025-01-30",
"asset_id": null,
"custody_account_id": null,
"cash_account_id": null,
"tag_id": null,
"currency_code": "DKK",
"units": null,
"market_value": "41.67"
},
{
"id": null,
"date": "2025-01-31",
"asset_id": null,
"custody_account_id": null,
"cash_account_id": null,
"tag_id": null,
"currency_code": "DKK",
"units": null,
"market_value": "83.33"
}
],
"next_cursor": null,
"limit": 1000,
"as_of": "2025-02-28"
}
Retrieve a holding
Returns one holding by the id of a list row (expand=assets,custody_accounts,cash_accounts): id, as_of (the holding's day, from the id), custody_account_id or cash_account_id (the account the holding sits on; the other is null), asset_id, currency_code (the id's currency leg), units, market_value, ownership_share, the share (0 to 1) units and market_value are weighted by, as on the list, reporting_currency and market_value_reporting. reporting_currency is the currency query parameter, the client's primary currency when left out; market_value_reporting is the same holding's leg in that currency, weighted the same way, and null when the holding has no leg in it. The holding is weighted by your ownership only: it reads no lens, so a lens's rules and start_date do not apply, and its numbers can differ from the same row read through a v1 lens. A holding on the legacy "No Depository" custody account sits on its cash account, as the list names it. An id with no holding behind it, on an account you cannot see, or on a day you own none of it, is a 404. An as_of query parameter must be the id's day; it, a currency outside the client's currencies and an unknown query parameter answer 400. Scope positions:read.
List a holding's look-throughs
Returns what a fund holding is made of, in the standard v1 list envelope, whose as_of is the holding's day. Client-fund rows come first, then the composition, each in a stable order.
Rows with source: "xray" are the fund's published composition (Morningstar), shared by every tenant: the composition the legacy holding points to, and the latest on or before the holding's day when it points to none (the row's as_of is the composition's date). Each row has isin, name, asset_id (an asset with that ISIN that you can see: the one the portfolio holds that day first, else the lowest id; null when there is none), tag_id (the component's detailed asset class as a tag, null when it has none), net_weight, gross_weight, weight (the net weight), currency_code, country_code, morningstar_security_id and market_value: the holding's market value times net_weight, in the holding's currency leg, as the legacy X-Ray report shows it (the report reads it in the report currency; here it follows the id's leg).
Rows with source: "client_fund" are the holdings a client fund owns on the holding's day, with asset_id, currency_code (the leg the underlying is valued in), units, market_value, weight and holding_kind. Every row carries every field; the ones its source does not fill are null. weight is the underlying's market value over the holding's, and null when the underlying is valued in another currency than the holding's leg. These rows belong to the fund, not to one currency leg: every leg id of the same fund lists them, so do not add them up across legs.
units and market_value are weighted by your ownership share as the holding is; the weights are fractions and stay as they are. A holding that is not a fund has no rows; an id with no holding behind it is a 404, and an as_of other than the id's day or an unknown query parameter a 400. limit (100 by default, 1 000 at most) and cursor page the rows. Scope positions:read.
List historical holdings
Returns the historical holdings of an account, as the legacy platform keeps them: the history from before Aleta (origin legacy) and the historical holdings written through the API (origin v1). Pass at least one of cash_account_id, custody_account_id and asset_id; from_date and to_date narrow on as_of_date. The standard v1 list envelope, ordered by as_of_date, then origin, then id; limit (100 by default, 1 000 at most) and cursor; an optional as_of (today when left out) names the date the answer is read at, and the history is the same whatever the date. An unknown parameter, an id that is not a UUID, no account or asset, or a to_date before from_date answers 400. Scope positions:read.
idstringThe legacy holding id on a legacy row, the row's UUID on a v1 row.
originstringlegacyorv1.kindstringaccount,assetorfee.as_of_dateISO 8601 dateThe day the holding is for.
holdingsdecimal string or nullUnits, or the balance of an account holding.
market_valuedecimal string or nullThe market value, in
currency_code.market_pricedecimal string or nullThe price the market value is at, and
market_price_date, its date.currency_exchange_ratedecimal string or nullThe exchange rate the holding was valued with.
return_amountdecimal string or nullThe return on the day.
external_movementdecimal string or nullMoney moved in or out on the day.
currency_codestringThe holding's currency.
holding_typestring or nullassetorredemptionon an asset holding,nullotherwise.tag_idstring or nullThe holding's classification as a tag,
nullwhen it has none.cash_account_idstring or nullThe cash account of an account or fee holding.
custody_account_idstring or nullThe custody account of an asset holding.
asset_idstring or nullThe asset of an asset or fee holding.
curl -G https://api.aleta.ai/v1/historical-holdings \
-H "Authorization: Bearer {access_token}" \
-d cash_account_id=019dff7d-5ab5-7ed4-a78d-93f03070e34b \
-d from_date=2020-01-01 \
-d to_date=2020-12-31
{
"data": [
{
"id": "5e8c1f2a9b3d4c0012ab34cd",
"origin": "legacy",
"kind": "account",
"as_of_date": "2020-03-31",
"holdings": "1000.5",
"market_value": "1000.5",
"market_price": null,
"market_price_date": null,
"currency_exchange_rate": "1",
"return_amount": "12.5",
"external_movement": "-3",
"currency_code": "DKK",
"holding_type": null,
"tag_id": "019dff7d-6a10-7c22-8e3b-1f2a3b4c5d6e",
"cash_account_id": "019dff7d-5ab5-7ed4-a78d-93f03070e34b",
"custody_account_id": null,
"asset_id": null
}
],
"next_cursor": null,
"limit": 100,
"as_of": "2026-10-18"
}
List tax lots
Returns the tax lots you can see, each as its latest snapshot on or before as_of (today when left out), ordered by lot id, in the standard v1 list envelope with as_of. Filters: cash_account_id, asset_id and status (open, partial or closed); limit (100 by default, 1 000 at most) and cursor. A filter id that is not a UUID, another status, an invalid cursor or an unknown query parameter answers 400. Scope positions:read.
A lot has id (the same across snapshots), as_of_date (the snapshot's day), cash_account_id, custody_account_id, asset_id, currency_code (the trade currency), source (custodian, computed, manual or unknown), external_id and external_source (the bank's own lot id and its source, when the bank delivered it), acquisition_date, original_units, remaining_units, cost_basis, basis_source (purchase, transfer_in, corporate_action, opening_balance or computed) and status. Where a custody account's lots come from is set with switch lot source.
Retrieve a tax lot
Returns one lot as its latest snapshot on or before as_of (today when left out), with the fields of the list and as_of, the date read. 404 when the id is not a UUID, the lot does not exist or you cannot see it, or it has no snapshot by as_of; an unknown query parameter is a 400. Scope positions:read.
List dispositions
Returns the dispositions you can see, the closings of units out of a lot, ordered by disposition_date, then id, in the standard v1 list envelope. Filters: cash_account_id, asset_id, lot_id, and from_date and to_date on disposition_date (both days included); limit (100 by default, 1 000 at most) and cursor. A filter id that is not a UUID, a to_date before from_date, an invalid cursor or an unknown query parameter answers 400. Scope positions:read.
A disposition has id, lot_id, transaction_id (the transaction that closed the units), cash_account_id, asset_id, currency_code, disposition_date, settle_date, units_closed, proceeds, cost_basis_used, realized_gain_loss, holding_period_days, external_id and external_source.
Related
- Performance — returns computed over the same scope.
- Lenses — the views holdings are read against.
- Transactions — the events that positions are built from.