View as Markdown

Historical uploads

Historical-holdings endpoints write holdings directly. There are three families: account holdings (cash), asset holdings (securities in a depository) and fee holdings, plus a bulk reclassification of asset holdings.

Common rules

  • Every attribute listed for a family is required. Numbers must be JSON numbers and dates strict yyyy-MM-dd; otherwise 400 Cannot parse request body. currencyCode/reportingCurrencyCode and classificationId may be null but must be present, and are then rejected by the validation below.
  • A relationship the family does not declare is 400 Resource of type '{type}' does not support relationship '{name}'., checked before the type.
  • A data.type other than the family's type is 409 Resource type '{type}' does not match the expected type of '{expected}'.
  • An unknown or invisible account, asset or depository is 404 '{account|asset|depository}' resource with ID '{id}' not found.
  • An unknown classificationId is checked after those: on account and asset holdings it is 500 An error occurred while processing your request.; on fee holdings it is the 404 below.
  • A second holding on the same natural key is 403 (texts per family below). Uploads are never overwritten.
  • The 201 echoes the attributes in the order listed, with every number as a decimal (5 becomes 5.0, 650.00 keeps its scale), the relationships, a new 24-character hex id and the type — in that member order.

POST/api/v2/historical-account-holdings

Upload account holdings

Books a historical holding on a cash account. Type historical-account-holding; relationship account.

Attributes

date, marketValue, holdings, return, externalMovement, currencyCode, classificationId.

Errors

  • 400 — '{currencyCode}' is not a valid currency code., then AccountId must not be null or empty., then ClassificationId must not be null or empty.
  • 403 — A historical account holding already exists for the given date and account.
Request
POST/api/v2/historical-account-holdings
curl -X POST https://api.aleta.ai/api/v2/historical-account-holdings \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "historical-account-holding",
      "attributes": {
        "date": "2025-07-01",
        "marketValue": 650.00,
        "holdings": 100.00,
        "return": 0.05,
        "externalMovement": 10.00,
        "currencyCode": "DKK",
        "classificationId": "68f132497c339ca9e9141234"
      },
      "relationships": {
        "account": { "data": { "type": "account", "id": "66f132497c339ca9e9141234" } }
      }
    }
  }'
Response
{
  "data": {
    "attributes": {
      "date": "2025-07-01",
      "marketValue": 650.00,
      "holdings": 100.00,
      "return": 0.05,
      "externalMovement": 10.00,
      "currencyCode": "DKK",
      "classificationId": "68f132497c339ca9e9141234"
    },
    "relationships": {
      "account": {
        "data": { "id": "66f132497c339ca9e9141234", "type": "account" }
      }
    },
    "id": "66f132497c339ca9e9145678",
    "type": "historical-account-holding"
  }
}

POST/api/v2/historical-asset-holdings

Upload asset holdings

Books a historical holding of an asset in a depository. Type historical-asset-holding; relationships asset and depository.

Attributes

date, marketPriceDate, marketValue, holdings, return, externalMovement, marketPrice, currencyExchangeRate, reportingCurrencyCode, classificationId, holdingType (asset or redemption; any other value is 400 Cannot parse request body.).

Errors

  • 400 — AssetId must not be null or empty., then DepositoryId must not be null or empty., then ClassificationId must not be null or empty., then 'ReportingCurrencyCode' must be an ISO 4217 currency code.
  • 403 — A historical asset holding already exists for the given date, asset, depository, and holdingType.
Request
POST/api/v2/historical-asset-holdings
curl -X POST https://api.aleta.ai/api/v2/historical-asset-holdings \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "historical-asset-holding",
      "attributes": {
        "date": "2025-07-01",
        "marketPriceDate": "2025-07-01",
        "marketValue": 650.00,
        "holdings": 100.00,
        "return": 0.05,
        "externalMovement": 0.00,
        "marketPrice": 6.50,
        "currencyExchangeRate": 100,
        "reportingCurrencyCode": "DKK",
        "classificationId": "68f132497c339ca9e9141234",
        "holdingType": "asset"
      },
      "relationships": {
        "asset": { "data": { "type": "asset", "id": "66f132497c339ca9e9141234" } },
        "depository": { "data": { "type": "depository", "id": "66f132497c339ca9e9145678" } }
      }
    }
  }'

POST/api/v2/historical-fee-holdings

Upload fee holdings

Books a historical fee holding for a fee asset on an account. Type historical-fee-holding; relationships asset (must be a fee asset) and account.

Attributes

date, return, externalMovement, reportingCurrencyCode, classificationId.

Errors

  • 400 — AssetId must not be null or empty., then AccountId must not be null or empty., then 'ReportingCurrencyCode' must be an ISO 4217 currency code., then ClassificationId must not be null or empty.
  • 404 — No classification found with ID '{classificationId}' for an unknown classification.
  • 403 — A historical fee holding already exists for the given date, fee, and account.
Request
POST/api/v2/historical-fee-holdings
curl -X POST https://api.aleta.ai/api/v2/historical-fee-holdings \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "historical-fee-holding",
      "attributes": {
        "date": "2025-07-01",
        "return": 100.00,
        "externalMovement": -100.00,
        "reportingCurrencyCode": "DKK",
        "classificationId": "68f132497c339ca9e9141234"
      },
      "relationships": {
        "asset": { "data": { "type": "asset", "id": "66f132497c339ca9e9141234" } },
        "account": { "data": { "type": "account", "id": "66f132497c339ca9e9145678" } }
      }
    }
  }'

Delete historical holdings

The three DELETE routes take no body; they delete every historical holding of the family in scope dated fromDate to toDate (inclusive) and return 200 with {"meta":{"recordsDeleted":N}}. Query parameter names are matched case-insensitively.

Validation, in order (the id rules apply to each id parameter of the route):

  • 400 — The ID '{id}' in '{parameter}' is not a valid ID format. (also when the id parameter is missing)
  • 400 — 'FromDate' must be specified exactly once. / 'ToDate' must be specified exactly once.
  • 400 — 'FromDate' must not be empty / 'FromDate' must be a valid date in the format 'yyyy-MM-dd'. (same for ToDate)
  • 400 — 'FromDate' must be less than or equal to 'ToDate'
  • 404 — Account not found. / Depository not found. for an account or depository you cannot see. An id that does not exist in the workspace at all is 500 Internal server error.

Delete account holdings

Query parameters: accountId, fromDate, toDate (all required).

Request
DELETE/api/v2/historical-account-holdings
curl -X DELETE -G https://api.aleta.ai/api/v2/historical-account-holdings \
  -H "Authorization: Bearer {access_token}" \
  -d accountId={account_id} \
  -d fromDate=2024-01-01 \
  -d toDate=2024-12-31
Response
{ "meta": { "recordsDeleted": 12 } }

Delete asset holdings

Query parameters: depositoryId, fromDate, toDate (all required). Deletes the depository's asset and redemption holdings in the range.

Request
DELETE/api/v2/historical-asset-holdings
curl -X DELETE -G https://api.aleta.ai/api/v2/historical-asset-holdings \
  -H "Authorization: Bearer {access_token}" \
  -d depositoryId={depository_id} \
  -d fromDate=2024-01-01 \
  -d toDate=2024-12-31

Delete fee holdings

Query parameters: accountId, assetId (the fee asset), fromDate, toDate (all required). An asset that is not a fee you can see is 404 Account not found.

Request
DELETE/api/v2/historical-fee-holdings
curl -X DELETE -G https://api.aleta.ai/api/v2/historical-fee-holdings \
  -H "Authorization: Bearer {access_token}" \
  -d accountId={account_id} \
  -d assetId={fee_asset_id} \
  -d fromDate=2024-01-01 \
  -d toDate=2024-12-31

POST/api/v2/historical-asset-holdings/reclassify

Reclassify asset holdings

Moves every historical holding of one asset from one classification to another and returns 200 with the number of rows changed. Type historical-asset-holdings-reclassify; relationship asset; attributes fromClassificationId and toClassificationId (both required keys). Reclassifying to the same classification changes nothing (rowsUpdated: 0).

Errors

  • 400 — Cannot parse request body. when a classification attribute is missing.
  • 409 — Resource type '{type}' does not match the expected type of 'historical-asset-holdings-reclassify'
  • 400 — AssetId must not be null or empty., then FromClassificationId must not be null or empty., then ToClassificationId must not be null or empty.
  • 404 No matching historical asset holdings found for the requested reclassification. when you cannot see the asset or one of the depositories holding it; nothing is updated.
  • 404 No classification found with ID '{classificationId}'. for an unknown classification (fromClassificationId is checked first).
Request
POST/api/v2/historical-asset-holdings/reclassify
curl -X POST https://api.aleta.ai/api/v2/historical-asset-holdings/reclassify \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "historical-asset-holdings-reclassify",
      "attributes": {
        "fromClassificationId": "68f132497c339ca9e9141234",
        "toClassificationId": "68f132497c339ca9e9145678"
      },
      "relationships": {
        "asset": { "data": { "type": "asset", "id": "66f132497c339ca9e9141234" } }
      }
    }
  }'
Response
{
  "data": {
    "attributes": { "rowsUpdated": 42 },
    "relationships": {
      "asset": {
        "data": { "id": "66f132497c339ca9e9141234", "type": "asset" }
      }
    },
    "id": null,
    "type": "historical-asset-holdings-reclassify"
  }
}