View as Markdown

Entities

Entities capture who legally owns the assets under a client — the holding companies, trusts, foundations, funds and natural persons in the ownership tree. Cash accounts and custody accounts attach to an entity, so the legal structure has to exist before custody data can land anywhere. Who owns an entity is an ownership, from a party or another entity.

Data model

idstring

Stable identifier for the entity. A UUID — treat it as opaque.

client_idstring

The client this entity belongs to. Set at creation, immutable afterwards.

namestring

Display name shown in the product.

kindstring

person, company, foundation, trust, fund or other.

primary_currencystring or null

ISO 4217 code of the entity's primary currency today: the one set through the API, else the one the entity was imported with, else its client's.

base_currenciesarray of strings

The primary currency first, then the entity's alternative currencies from the legacy platform, without duplicates.

valid_fromstring or null

The entity's first day (YYYY-MM-DD), null when it has always held.

valid_tostring or null

The entity's last day (YYYY-MM-DD), null while it is open. A closed client ends its entities.

closed_throughstring or null

The entity's period is closed up to and including this date (YYYY-MM-DD): a write dated on or before it, on a cash or custody account the lock covers, answers 409 period_locked. null when nothing is closed. Set it with the period lock. Until your move to v1 is done the legacy platform's monthly lock is the one that counts, and this field stays null.

originstring

legacy for an entity mirrored from the legacy platform, v1 for one made through this API.

Every write on this page takes ?dry_run=true and an Idempotency-Key header, and logs each changed row in the change list. A row that comes from the legacy platform answers 409 legacy_managed until your move to v1 is done. An unknown body field is 400. Writing an entity takes a grant that covers it whole — the tenant, its client or a client above it, or the entity itself (a new entity: its client) — and is not read-only: anyone else gets 403. Admins and Aleta write everywhere. A refusal comes in that order: 404, then 403, then 409.


GET/v1/entities

List entities

Returns every entity visible to the authenticated credential, across all clients it can reach, in the standard v1 list envelope.

Query parameters

client_idstring

Only the entities of this client. A malformed id is a 400; a client you cannot see lists nothing.

limitinteger

Page size. Defaults to 100, capped at 1 000.

cursorstring

Opaque cursor from the previous page's next_cursor. Omit for the first page.

Request
GET/v1/entities
curl -G https://api.aleta.ai/v1/entities \
  -H "Authorization: Bearer {access_token}" \
  -d client_id=019dfeb0-0511-77a7-a8be-a911ab988a0a \
  -d limit=2
Response
{
  "data": [
    {
      "id": "019dfed3-168e-7cdc-83b2-7598704282f0",
      "client_id": "019dfeb0-0511-77a7-a8be-a911ab988a0a",
      "name": "LE renamed",
      "kind": "company",
      "primary_currency": "DKK",
      "base_currencies": ["DKK", "EUR"],
      "valid_from": null,
      "valid_to": null,
      "closed_through": null,
      "origin": "legacy"
    },
    {
      "id": "019eb3d2-fc2e-7782-973e-af78d0c10fa6",
      "client_id": "019dfeb0-0511-77a7-a8be-a911ab988a0a",
      "name": "Testing LegalEntity1",
      "kind": "person",
      "primary_currency": "DKK",
      "base_currencies": ["DKK"],
      "valid_from": null,
      "valid_to": null,
      "closed_through": null,
      "origin": "v1"
    }
  ],
  "next_cursor": "MjAyNi0wNi0xMCAyMzoxNjo0OS4zMjY1MDQrMDB8MDE5ZWIzZDItZmMyZS03NzgyLTk3M2UtYWY3OGQwYzEwZmE2",
  "limit": 2
}

POST/v1/entities

Create an entity

Creates an entity under an existing client. Returns 201 with the created resource.

Body parameters

client_idstring

The client to create the entity under. Required.

namestring

Display name. Required, not blank.

kindstring

person, company, foundation, trust, fund or other. Required.

primary_currencystring

ISO 4217 code, three letters A-Z. Optional, DKK when left out.

Request
POST/v1/entities
curl -X POST https://api.aleta.ai/v1/entities \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "019dfeb0-0511-77a7-a8be-a911ab988a0a",
    "name": "Testing LegalEntity1",
    "kind": "person"
  }'
Response
{
  "id": "019eb3d2-fc2e-7782-973e-af78d0c10fa6",
  "client_id": "019dfeb0-0511-77a7-a8be-a911ab988a0a",
  "name": "Testing LegalEntity1",
  "kind": "person",
  "primary_currency": "DKK",
  "base_currencies": ["DKK"],
  "valid_from": null,
  "valid_to": null,
  "closed_through": null,
  "origin": "v1"
}

GET/v1/entities/{id}

Retrieve an entity

Fetch a single entity by id. Returns the bare object, or a 404 problem when the id doesn't exist for this tenant.

Request
GET/v1/entities/{id}
curl https://api.aleta.ai/v1/entities/019dfed3-168e-7cdc-83b2-7598704282f0 \
  -H "Authorization: Bearer {access_token}"
Response
{
  "id": "019dfed3-168e-7cdc-83b2-7598704282f0",
  "client_id": "019dfeb0-0511-77a7-a8be-a911ab988a0a",
  "name": "LE renamed",
  "kind": "company",
  "primary_currency": "DKK",
  "base_currencies": ["DKK", "EUR"],
  "valid_from": null,
  "valid_to": null,
  "closed_through": null,
  "origin": "legacy"
}

PATCH/v1/entities/{id}

Update an entity

Partially updates an entity. Only the fields present in the body are touched. client_id is immutable — an entity cannot move between clients.

Without effective_from the call is a correction: the entity was wrong all along. With effective_from it is a change of the primary currency from that day: the currency in force on the date ends the day before, the new one starts on it, and what stood before stays. A recalculation of the entity's figures from that day is queued. Both are logged with reason.

Body parameters

namestring

New display name. Must not be blank.

kindstring

person, company, foundation, trust, fund or other.

primary_currencystring

ISO 4217 code, three letters A-Z. null is a 422: an entity always has one.

effective_fromstring

YYYY-MM-DD, today or earlier (a later day is 422 effective_from_in_future): the day the new primary_currency starts. Only with primary_currency and no name, kind or valid_to; otherwise 422 effective_from_currency_only.

valid_tostring or null

The entity's last day, or null to open it again. Not before valid_from (400).

reasonstring

Why, for the change list. Optional, not blank.

A body without name, kind, primary_currency or valid_to is 422 empty_patch; primary_currency: null is 422 currency_required.

Ending an entity changes nothing else: its cash and custody accounts, the economic ownerships it is owner or owned in, and its tag assignments keep their own periods. The answer is the entity plus warnings: for a valid_to date, each of those rows that still holds after that day, as {code: "open_after_end", kind, id, valid_to}, with kind cash_account, custody_account, ownership or tag_assignment and the row's own last day (null when open), ordered by kind and id. End each one on its own route. Any other PATCH answers warnings: [].

Request
PATCH/v1/entities/{id}
curl -X PATCH https://api.aleta.ai/v1/entities/019dfed3-168e-7cdc-83b2-7598704282f0 \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{ "primary_currency": "EUR", "effective_from": "2026-01-01", "reason": "moved to Germany" }'
Response
{
  "id": "019dfed3-168e-7cdc-83b2-7598704282f0",
  "client_id": "019dfeb0-0511-77a7-a8be-a911ab988a0a",
  "name": "LE renamed",
  "kind": "company",
  "primary_currency": "EUR",
  "base_currencies": ["EUR"],
  "valid_from": null,
  "valid_to": null,
  "closed_through": null,
  "origin": "v1",
  "warnings": []
}

DELETE/v1/entities/{id}

Delete an entity

Removes an entity that nothing uses. Returns 204 on success, 404 if the id doesn't exist for this tenant.

An entity with cash or custody accounts, transactions, holdings, figures computed on it, custodian positions, reconciliation breaks, ownerships, tags, custodian authorities, access grants, dated currency versions, price, exchange-rate or basic-data hierarchies set on it, documents, lens rules that name it, or assets built on it is not deleted: the answer is 409 in_use, and next_action points to PATCH /v1/entities/{id} with valid_to, which ends it instead.

A lens that only holds the entity through a broader rule, such as the client's structure lens (include client), does not block the delete. Neither do cash and custody accounts that were deleted before it. The entity leaves those lenses when it is deleted.

Request
DELETE/v1/entities/{id}
curl -X DELETE https://api.aleta.ai/v1/entities/019eb3d2-fc2e-7782-973e-af78d0c10fa6 \
  -H "Authorization: Bearer {access_token}"

GET/v1/entities/{id}/owners

List an entity's owners

Who owns the entity on as_of (default today), with the owner's name, in the standard v1 list envelope with as_of. Same fields as an ownership, with ownership_id and owner_name. 404 if you cannot see the entity. Any other query parameter is a 400.

Query parameters

as_ofstring

YYYY-MM-DD. Defaults to today.

limitinteger

Page size. Defaults to 100, capped at 1 000.

cursorstring

Opaque cursor from the previous page's next_cursor.

Request
GET/v1/entities/{id}/owners
curl https://api.aleta.ai/v1/entities/019eb3d2-fc2e-7782-973e-af78d0c10fa6/owners \
  -H "Authorization: Bearer {access_token}"

Ownerships

An ownership says that a party or an entity owns a share of an entity for a period. v1 records economic ownership only: there is no basis, and a voting-only row from the legacy platform is not shown.

idstring

Stable identifier for the ownership.

owner_kindstring

party or entity.

owner_idstring

The owning party or entity.

owned_entity_idstring

The entity owned.

percentagestring

The share, a decimal string from 0 to 100.

valid_fromstring or null

The first day, null when it has always held.

valid_tostring or null

The last day, null while it is open.

custody_account_idsarray or null

null when the ownership covers the whole entity; else the custody accounts it covers that are open on the day read (as_of, else today).

cash_account_idsarray or null

null when the ownership covers the whole entity; else the cash accounts it covers that are open on the day read (as_of, else today).

created_atstring

When it was recorded.

originstring

legacy or v1.


GET/v1/ownerships

List ownerships

Every ownership in force on as_of (default today) that you can see, ordered by owned entity, start and id, in the standard v1 list envelope with as_of. Takes as_of, limit and cursor; any other query parameter is a 400.

Request
GET/v1/ownerships
curl -G https://api.aleta.ai/v1/ownerships \
  -H "Authorization: Bearer {access_token}" \
  -d as_of=2026-10-18

GET/v1/ownerships/{id}

Retrieve an ownership

One ownership by id, whatever its period. 404 when it doesn't exist, you cannot see it, or it is a voting-only row.

Request
GET/v1/ownerships/{id}
curl https://api.aleta.ai/v1/ownerships/019f9a10-6b2c-7d11-a0f4-3c9e2b8d4e55 \
  -H "Authorization: Bearer {access_token}"

POST/v1/ownerships

Create an ownership

Records that a party or an entity owns a share of an entity from valid_from (and up to valid_to, the last day, when it ends).

The economic shares of an entity may not pass 100 % on any of its cash or custody accounts on any day: that answers 400 ownership_over_100. Shares under 100 % are allowed while you build the structure, and the answer then carries a warning in warnings. An ownership that would make an entity own itself answers 400 ownership_cycle. The same owner owning the same entity in an overlapping period answers 409 ownership_overlap, with next_action on the existing ownership (PATCH, effective_from): change that one instead. A voting-only ownership does not count.

Body parameters

owner_kindstring

party or entity. Required.

owner_idstring

The owning party or entity. Required.

owned_entity_idstring

The entity owned. Required.

percentagestring

The share, a decimal string from 0 to 100. Required.

valid_fromstring

The first day. Required.

valid_tostring

The last day. Optional.

Response fields

warningsarray

shares_below_100 when the cash and custody accounts the ownership covers hold less than 100 % on some day of its period: allocated_percentage is the lowest sum in the period and on the first day it holds. Empty when they hold 100 %.

Request
POST/v1/ownerships
curl -X POST https://api.aleta.ai/v1/ownerships \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "owner_kind": "party",
    "owner_id": "019eb3d2-fc2e-7782-973e-af78d0c10f01",
    "owned_entity_id": "019eb3d2-fc2e-7782-973e-af78d0c10fa6",
    "percentage": "40",
    "valid_from": "2026-01-01"
  }'
Response
{
  "id": "019f9a10-6b2c-7d11-a0f4-3c9e2b8d4e55",
  "owner_kind": "party",
  "owner_id": "019eb3d2-fc2e-7782-973e-af78d0c10f01",
  "owned_entity_id": "019eb3d2-fc2e-7782-973e-af78d0c10fa6",
  "percentage": "40.0000000000",
  "valid_from": "2026-01-01",
  "valid_to": null,
  "custody_account_ids": null,
  "cash_account_ids": null,
  "created_at": "2026-10-16T12:00:00Z",
  "origin": "v1",
  "warnings": [
    { "code": "shares_below_100", "on": "2026-01-01", "allocated_percentage": "40.0000000000" }
  ]
}

PATCH/v1/ownerships/{id}

Change an ownership

Corrects an ownership, or changes its share from a date. Returns 200 with the resulting ownership and warnings as on create, 404 if you cannot see the ownership, its owner, a new owner or the entity it owns.

Without effective_from the call is a correction: the ownership was wrong all along, and it is rewritten in its whole period under the same id. You may send percentage, owner_kind with owner_id, valid_from and valid_to (null for open-ended).

With effective_from the call is a change: the share is new from that day. The ownership ends the day before, and a new ownership with the new percentage runs from effective_from to the old end; the answer is the new one. Only percentage goes with effective_from, and the date must fall inside the ownership's period.

Both are logged as a change with reason. The share and cycle rules of create apply (400 ownership_over_100, 400 ownership_cycle), and a second ownership of the same owner starting the same day is 409 ownership_overlap. The owned entity cannot be changed.

Request fields

percentagestring

The share, a decimal string from 0 to 100.

owner_kindstring

party or entity, with owner_id. Correction only.

valid_fromstring

The first day. Correction only.

valid_tostring

The last day, or null. Correction only.

effective_fromstring

The day the new share starts.

reasonstring

Why, for the change list.

Request
PATCH/v1/ownerships/{id}
curl -X PATCH https://api.aleta.ai/v1/ownerships/019f9a10-6b2c-7d11-a0f4-3c9e2b8d4e55 \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{ "percentage": "50", "effective_from": "2027-01-01", "reason": "share purchase" }'
Response
{
  "id": "019f9a10-7c3d-7e22-b1a5-4d0f3c9e5f66",
  "owner_kind": "party",
  "owner_id": "019eb3d2-fc2e-7782-973e-af78d0c10f01",
  "owned_entity_id": "019eb3d2-fc2e-7782-973e-af78d0c10fa6",
  "percentage": "50.0000000000",
  "valid_from": "2027-01-01",
  "valid_to": null,
  "custody_account_ids": null,
  "cash_account_ids": null,
  "created_at": "2026-10-17T09:00:00Z",
  "origin": "v1",
  "warnings": [
    { "code": "shares_below_100", "on": "2027-01-01", "allocated_percentage": "50.0000000000" }
  ]
}

DELETE/v1/ownerships/{id}

Delete an ownership

Removes an ownership no figure ever rested on, for a typing mistake. Returns 204, 404 if you cannot see the ownership, its owner or the entity it owns.

An ownership is used once its period holds data in the cash and custody accounts it reaches: transactions before it ends, or holdings, net asset values, custodian positions or manual holdings inside it, also further down through entities the owned entity owns. A used ownership answers 409 in_use with next_action end_date on PATCH /v1/ownerships/{id} (valid_to).

Request
DELETE/v1/ownerships/{id}
curl -X DELETE https://api.aleta.ai/v1/ownerships/019f9a10-6b2c-7d11-a0f4-3c9e2b8d4e55 \
  -H "Authorization: Bearer {access_token}"

PUT/v1/entities/{id}/period-lock

Set the period lock

Closes an entity's period up to and including closed_through, or opens it again. The date is stored on the entity only. Two more routes take the same body and set the same date on several entities in one call: PUT /v1/clients/{id}/period-lock (the client's own entities) and PUT /v1/tenants/current/period-lock (every entity). There is no DELETE: an earlier date opens the days after it, and null opens everything.

Once a period is closed, a write dated on or before the date on a cash or custody account the lock covers answers 409 period_locked. To correct something in a closed period: unlock, register, then lock again. Each move is logged as a change (lock or unlock) with its reason.

Only an admin sets the lock (Aleta too, when every cash and custody account the call covers is one Aleta runs); anyone else gets 403 forbidden. Until your move to v1 is done the legacy platform's monthly lock is the one that counts, so the routes answer 409 legacy_managed. A refusal comes in that order: 400 for the body, 404 for an entity or client you cannot see, then 403, then 409. Takes dry_run and Idempotency-Key: a dry run answers what the call would lock and open, and changes nothing.

Body parameters

closed_throughstring or null

YYYY-MM-DD, today or earlier, or null to open everything. Required. A date in the future is a 400.

reasonstring

Why, for the change log. Optional.

Response

closed_throughstring or null

The date the call set.

entitiesarray

Every entity the call covers, by id, with entity_id, previous_closed_through and closed_through.

lockedarray

The covered cash and custody accounts (kind, id, entity_id) of the entities whose closed period grew.

unlockedarray

The covered cash and custody accounts of the entities whose closed period shrank.

Request
PUT/v1/entities/{id}/period-lock
curl -X PUT https://api.aleta.ai/v1/entities/019dfed3-168e-7cdc-83b2-7598704282f0/period-lock \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{ "closed_through": "2026-09-30", "reason": "Q3 closed" }'
Response
{
  "closed_through": "2026-09-30",
  "entities": [
    {
      "entity_id": "019dfed3-168e-7cdc-83b2-7598704282f0",
      "previous_closed_through": null,
      "closed_through": "2026-09-30"
    }
  ],
  "locked": [
    {
      "kind": "cash_account",
      "id": "019dfed4-2a1b-7c3d-9e4f-5a6b7c8d9e0f",
      "entity_id": "019dfed3-168e-7cdc-83b2-7598704282f0"
    }
  ],
  "unlocked": []
}
  • Parties — the persons and organisations that own entities.
  • Cash accounts — the cash accounts attached to an entity.
  • Custody accounts — where an entity's assets physically sit.
  • Clients — the client an entity belongs to.