View as Markdown

Tags

Tags are the classification system: named nodes in a taxonomy (asset classes, regions, sectors, custom groupings) that get attached to targets through tag assignments. The tag defines what a classification is; the assignment says which target carries it, from when, and at what scope. Reading requires the reporting:read scope, and so does previewing a tag's rule, which writes nothing; every other write requires reporting:write.

There are two layers, told apart by owner. Aleta's shared tags (owner: "aleta") are the same for every tenant: the GICS sectors and industries, and the standard asset classification with its default assignments. You read them and assign them, but you cannot change or remove them (403 aleta_owned). Your own tags and assignments (owner: "tenant") sit on top: a tag of your own, or an override of a shared tag named in base_tag_id, and the assignments you make, which take precedence over the default ones.

Data model

idstring

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

base_tag_idstring or null

The Aleta reference tag this tag overrides, when it overrides one.

taxonomy_codestring or null

The taxonomy the tag belongs to, e.g. legacy_classification.

codestring or null

Machine-readable code within the taxonomy.

parent_tag_idstring or null

Parent tag in the hierarchy. null for roots.

namestring

Display name shown in the product.

patternstring or null

How a tag of yours relates to Aleta's: tenant_only for a tag of its own, extend, override_subtree or replace_whole_tree for an override of the shared tag in base_tag_id. null on Aleta's tags.

matchobject, array or null

Optional match rule for automatic assignment, as it was written: one predicate or an array of them.

valid_fromISO 8601 date or null

First date the tag applies. null means no start.

valid_toISO 8601 date or null

Last date the tag applies. null means open-ended.

statusstring

active when the tag applies on the day read (as_of in a list, today otherwise), else inactive. An Aleta reference tag (GICS) has no dates: it is active until Aleta retires it, and a list shows only active ones.

ownerstring

aleta for Aleta's shared tags, tenant for yours.

originstring

legacy for a tag that came from the legacy platform (Aleta's shared tags among them), v1 for one made through this API.

metadataobject

Free-form metadata carried on the tag. balance_post_id, the accounting balance post of a legacy classification, is a string like every other id ("7").


GET/v1/tags

List tags

Returns tags in the standard v1 list envelope: Aleta's reference tags (GICS) first, then the tags kept for your tenant (Aleta's standard classification and your own) in the order they were created; one page can hold both. A reference tag has no dates and is listed while it is active. Any other tag is listed on the days it applies: from valid_from through valid_to, read on as_of. One that ended before as_of is left out unless include_expired=true; one that starts after it is always left out.

Query parameters

as_ofISO 8601 date

The day the tags are read on, shown in as_of. Defaults to today.

ownerstring

aleta or tenant for one layer. Both when left out. Anything else is a 400.

include_expiredboolean

Also list the tags that ended before as_of, with status: "inactive". Defaults to false.

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. A cursor that cannot be read is a 400.

Any other parameter is a 400.

Request
GET/v1/tags
curl -G https://api.aleta.ai/v1/tags \
  -H "Authorization: Bearer {access_token}" \
  -d limit=2
Response
{
  "data": [
    {
      "id": "019f106f-59a2-71dc-9d28-e9069a50a4ea",
      "base_tag_id": null,
      "taxonomy_code": "gics",
      "code": "10",
      "parent_tag_id": null,
      "name": "Energy",
      "pattern": null,
      "match": null,
      "valid_from": null,
      "valid_to": null,
      "status": "active",
      "owner": "aleta",
      "origin": "legacy",
      "metadata": {
        "gics_level": "sector"
      }
    },
    {
      "id": "019e93ad-6ed9-72fa-b817-e463aaee1662",
      "base_tag_id": null,
      "taxonomy_code": "legacy_classification",
      "code": "6a0443600f1c409c6873c522",
      "parent_tag_id": null,
      "name": "Indlån DKK",
      "pattern": null,
      "match": null,
      "valid_from": "2024-06-01",
      "valid_to": null,
      "status": "active",
      "owner": "aleta",
      "origin": "legacy",
      "metadata": {
        "last_modified": null
      }
    }
  ],
  "next_cursor": "dGVuYW50fDIwMjYtMDYtMDQgMTc6Mjc6NTcuMzAwNTA3KzAwfDAxOWU5M2FkLTZlZDktNzJmYS1iODE3LWU0NjNhYWVlMTY2Mg",
  "limit": 2,
  "as_of": "2026-10-18"
}

POST/v1/tags

Create a tag

Creates a tag of your own. Only name is required. Returns 201 with the created tag. Takes ?dry_run=true and Idempotency-Key. A base_tag_id that is not one of Aleta's reference tags, or a parent_tag_id that is not one of the tags kept for your tenant, answers 404. An unknown field is a 400.

Body parameters

namestring

Display name. Required; an empty name is a 400.

taxonomy_codestring

Taxonomy to file the tag under. Optional. The taxonomies of Aleta's shared tags (legacy_classification, asset_class, asset_class_detailed, gics, morningstar, risk_country) are refused with 400; to override one of those tags, name it in base_tag_id.

codestring

Machine-readable code within the taxonomy. Optional.

parent_tag_idstring

Parent tag for hierarchy placement. Optional.

base_tag_idstring

The Aleta reference tag this one overrides. Optional; required with an override pattern.

patternstring

tenant_only (the default) for a tag of its own, which must omit base_tag_id, or extend, override_subtree or replace_whole_tree for an override, which needs base_tag_id. Anything else is a 400.

matchobject or array

Match rule for automatic assignment. Optional. One predicate or an array of them, all of which must hold: {"field": "currency_code", "op": "=", "value": "DKK"}. op is =, !=, in, not_in, >, >=, < or <=; field is an asset field (name, kind, isin, currency_code, country_code, ...) or metadata.<key>. A rule the preview cannot read is refused with 400 and the reason.

valid_fromISO 8601 date

First date the tag applies; today when omitted. Optional, like valid_to (the last date it applies). A valid_from after valid_to is a 400.

metadataobject

Free-form metadata. Optional.

Request
POST/v1/tags
curl -X POST https://api.aleta.ai/v1/tags \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Core holdings",
    "taxonomy_code": "house_view",
    "code": "core"
  }'
Response
{
  "id": "01a14e88-af2b-7298-b166-842476dd361f",
  "base_tag_id": null,
  "taxonomy_code": "house_view",
  "code": "core",
  "parent_tag_id": null,
  "name": "Core holdings",
  "pattern": "tenant_only",
  "match": null,
  "valid_from": "2026-10-18",
  "valid_to": null,
  "status": "active",
  "owner": "tenant",
  "origin": "v1",
  "metadata": {}
}

GET/v1/tags/{id}

Retrieve a tag

Fetch a single tag by id, one of yours or one of Aleta's shared tags. status is read on today. Returns the bare object, or a 404 problem when the id is neither.

Request
GET/v1/tags/{id}
curl https://api.aleta.ai/v1/tags/019e93ad-6ed9-72fa-b817-e463aaee1662 \
  -H "Authorization: Bearer {access_token}"
Response
{
  "id": "019e93ad-6ed9-72fa-b817-e463aaee1662",
  "base_tag_id": null,
  "taxonomy_code": "legacy_classification",
  "code": "6a0443600f1c409c6873c522",
  "parent_tag_id": null,
  "name": "Indlån DKK",
  "pattern": null,
  "match": null,
  "valid_from": "2024-06-01",
  "valid_to": null,
  "status": "active",
  "owner": "aleta",
  "origin": "legacy",
  "metadata": {
    "last_modified": null
  }
}

PATCH/v1/tags/{id}

Update a tag

Partially updates a tag and returns 200 with it. Every field from create is patchable; base_tag_id, taxonomy_code, code, parent_tag_id, match and valid_to can be cleared by passing null explicitly. Omitted fields are unchanged; metadata, when sent, replaces the tag's metadata. The same rules as on create apply to name, pattern, taxonomy_code, match and the dates. Takes ?dry_run=true and Idempotency-Key.

An update corrects the tag for its whole life and is logged as a change with an optional reason (a string in the body). A parent_tag_id that is the tag itself or would make it its own ancestor answers 400; an unknown id answers 404. One of Aleta's shared tags answers 403 aleta_owned, before and after your move, and so do Aleta's reference tags (GICS) always; any other tag from the legacy platform answers 409 legacy_managed until your move to v1 is done. An unknown field is a 400.

Request
PATCH/v1/tags/{id}
curl -X PATCH https://api.aleta.ai/v1/tags/01a14e88-af2b-7298-b166-842476dd361f \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{ "valid_to": "2026-12-31", "reason": "House view ends this year" }'

DELETE/v1/tags/{id}

Delete a tag

Removes a tag nothing uses (204). A tag that is assigned, has child tags or is the target of a limit, benchmark, hierarchy, document or lens rule is ended instead: its valid_to and that of its open assignments are set to ?valid_to= (today when left out), and the answer is 200 with the tag. Pass ?valid_to= to end an unused tag too. A date before the tag's valid_from is a 400; a tag that already ends on or before the day answers 200 unchanged.

A child tag that runs past the day, or an assignment that starts after it, answers 409 in_use: next_action points to the child (DELETE /v1/tags/{id} with valid_to) or the assignment (DELETE /v1/tag-assignments/{id}). Ending a tag that has open assignments you cannot see also answers 409 in_use, without next_action. An open assignment that would end up the same as one already ending on that day answers 409 conflict. One of Aleta's shared tags answers 403 aleta_owned, before and after your move, and so do Aleta's reference tags (GICS) always; any other tag from the legacy platform answers 409 legacy_managed until your move to v1 is done. Takes ?dry_run=true and Idempotency-Key; 404 if the id doesn't exist for this tenant.

Request
DELETE/v1/tags/{id}
curl -X DELETE "https://api.aleta.ai/v1/tags/01a14e88-af2b-7298-b166-842476dd361f?valid_to=2026-12-31" \
  -H "Authorization: Bearer {access_token}"

POST/v1/tags/{id}/preview

Preview a tag's assignments

Runs the tag's match rule over the assets you hold, without writing anything; it needs reporting:read. The assets are those held on the newest holdings date on or before as_of (today when left out) that you can see. Each match comes with one reason per predicate and whether the tag is already assigned on that day. The tag must be one kept for your tenant: Aleta's reference tags (GICS) and unknown ids answer 404. A tag without a rule answers 400.

Body parameters (optional)

as_ofISO 8601 date

The day to read holdings on; the newest holdings date on or before it is used. Today when left out.

limitinteger

How many matches data holds; matched counts them all. Defaults to 100, capped at 1 000.

An empty body is the same as {}. Any other field, or a body that is not JSON, is a 400.

Response fields

tag_idstring

The tag previewed.

as_ofISO 8601 date or null

The holdings date used; null when you hold nothing.

evaluated, matchedinteger

Assets the rule ran over, and how many matched.

limitinteger

The page size applied to data.

dataarray

Per match: asset_id, name, isin (string or null), already_assigned (boolean) and reasons, one line per predicate.

Request
POST/v1/tags/{id}/preview
curl -X POST https://api.aleta.ai/v1/tags/01a14e8c-3d2e-7c41-8f0a-5b6e7d8c9a01/preview \
  -H "Authorization: Bearer {access_token}"
Response
{
  "tag_id": "01a14e8c-3d2e-7c41-8f0a-5b6e7d8c9a01",
  "as_of": "2026-10-17",
  "evaluated": 214,
  "matched": 1,
  "limit": 100,
  "data": [
    {
      "asset_id": "019e2c98-b0ea-7c57-81b7-c0c3fac715e7",
      "name": "Danske Bank A/S",
      "isin": "DK0010274414",
      "already_assigned": false,
      "reasons": [
        "currency_code = \"DKK\" (holds: 'DKK')"
      ]
    }
  ]
}

GET/v1/tag-assignments

List tag assignments

Returns tag assignments — the edges connecting tags to their targets — in effect on as_of (a date, today when left out, shown in the envelope), in the standard v1 list envelope. An assignment whose valid_from is after as_of is left out, and so is one whose valid_to is before it unless include_expired=true. Aleta's default assignment of an asset and one you made are both listed; where both apply, yours takes precedence.

You see the assignments of what you have access to: one scoped to an entity needs that entity, and one on a holding, transaction, document or lens needs that target. An asset is shared, so an asset assignment without a scope shows to everyone with reporting:read, except on an asset a client owns, which shows only to those who see that asset. Tenant owners and tenant admins see every assignment.

Query parameters

as_of, limit and cursor as on every v1 list, and:

tag_id, target_kind, target_idstring

Only the assignments of this tag, this kind of target, or this target. tag_id and target_id must be UUIDs, else 400.

ownerstring

aleta for Aleta's default assignments, tenant for yours. Both when left out. Anything else is a 400.

include_expiredboolean

Also list the assignments that ended before as_of. Defaults to false.

Any other parameter is a 400.

Assignment fields

idstring

Stable identifier for the assignment.

target_kindstring

What kind of thing is tagged: asset, holding, transaction, document or lens.

target_idstring

Identifier of the tagged target.

tag_idstring

The tag being assigned.

sourcestring

How the assignment came to be: default for Aleta's standard classification, manual for one made by hand, rule or ai for a derived one.

ownerstring

aleta for a default assignment, tenant for the rest.

originstring

legacy or v1, as on a tag.

scope_entity_idstring or null

Restricts the assignment to one entity's view, when set.

confidencedecimal string or null

Confidence score for rule-derived assignments.

valid_fromISO 8601 date or null

First date the assignment applies. null means no start.

valid_toISO 8601 date or null

Last date the assignment applies. null means open-ended.

metadataobject

Free-form metadata carried on the assignment.

Request
GET/v1/tag-assignments
curl -G https://api.aleta.ai/v1/tag-assignments \
  -H "Authorization: Bearer {access_token}" \
  -d limit=2
Response
{
  "data": [
    {
      "id": "019e96e3-8d71-7296-bf6f-39e5fbe1f25b",
      "target_kind": "asset",
      "target_id": "019e2c98-b0ea-7c57-81b7-c0c3fac715e7",
      "tag_id": "019e93fd-66c1-7a7d-bf11-f35ee5d22ecb",
      "source": "default",
      "owner": "aleta",
      "origin": "legacy",
      "scope_entity_id": null,
      "confidence": null,
      "valid_from": null,
      "valid_to": null,
      "metadata": {}
    },
    {
      "id": "01a14e89-1050-7dea-9609-99a3b1fc77f3",
      "target_kind": "asset",
      "target_id": "019e2c98-b0ea-7c57-81b7-c0c3fac715e7",
      "tag_id": "01a14e88-af2b-7298-b166-842476dd361f",
      "source": "manual",
      "owner": "tenant",
      "origin": "v1",
      "scope_entity_id": null,
      "confidence": null,
      "valid_from": null,
      "valid_to": null,
      "metadata": {}
    }
  ],
  "next_cursor": "MjAyNi0xMC0xOCAxMDoyMTo0MC4xMjM0NTYrMDB8MDFhMTRlODktMTA1MC03ZGVhLTk2MDktOTlhM2IxZmM3N2Yz",
  "limit": 2,
  "as_of": "2026-10-18"
}

POST/v1/tag-assignments

Create a tag assignment

Attaches a tag to a target: one of yours, or an active one of Aleta's reference tags (a GICS sector, say), which keys on its taxonomy as yours do. Its source is manual. A target holds one manual tag per taxonomy (a tag without a taxonomy only itself) and entity scope at a time, so a new tag in the same taxonomy replaces the one there:

  • without effective_from it replaces it in its whole period (a correction), and the answer is 200 with that assignment;
  • with effective_from the old assignment ends the day before and a new one runs from that day (a change), answered 201;
  • when no assignment of the taxonomy is in force on that day (today, or effective_from), a new one runs from effective_from, else valid_from, else from where the last one ended, else from the beginning, answered 201.

The same tag already in force answers 200 and writes nothing. An effective_from equal to the start of the assignment in force is a correction (200). A new period that runs into another assignment of the taxonomy answers 409 conflict. Defaults set by Aleta's classification are never replaced. An unknown tag, a retired reference tag, or a target or scope_entity_id you cannot see, answers 404. A tag of Aleta's standard classification, or replacing an assignment from the legacy platform, answers 409 legacy_managed until your move to v1 is done. Takes ?dry_run=true and Idempotency-Key; each write is logged as a change with reason. An unknown field is a 400. The answer carries the assignment.

Body parameters

target_kindstring

What kind of thing to tag: asset, holding, transaction, document or lens. Required; anything else is a 400.

target_idstring

Identifier of the target, a UUID. Required.

tag_idstring

The tag to assign, a UUID. Required.

scope_entity_idstring

Restrict the assignment to one entity's view. Optional.

valid_fromISO 8601 date

First date a new assignment applies. Optional, like valid_to, its last day. A valid_from (or effective_from) after valid_to is a 400.

effective_fromISO 8601 date

The day the tag replaces the one in force. Optional; sending it with valid_from is a 400.

reasonstring

Why, for the change list. Optional.

metadataobject

Free-form metadata. Optional.

Request
POST/v1/tag-assignments
curl -X POST https://api.aleta.ai/v1/tag-assignments \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "target_kind": "asset",
    "target_id": "019e2c98-b0ea-7c57-81b7-c0c3fac715e7",
    "tag_id": "01a14e88-af2b-7298-b166-842476dd361f"
  }'
Response
{
  "id": "01a14e89-1050-7dea-9609-99a3b1fc77f3",
  "target_kind": "asset",
  "target_id": "019e2c98-b0ea-7c57-81b7-c0c3fac715e7",
  "tag_id": "01a14e88-af2b-7298-b166-842476dd361f",
  "source": "manual",
  "owner": "tenant",
  "origin": "v1",
  "scope_entity_id": null,
  "confidence": null,
  "valid_from": null,
  "valid_to": null,
  "metadata": {}
}

DELETE/v1/tag-assignments/{id}

Delete a tag assignment

Detaches a tag from its target by removing the assignment. The tag itself is untouched. Returns 204 on success, 404 if the id doesn't exist for this tenant or hangs on a target or entity you cannot see. One of Aleta's default assignments answers 403 aleta_owned; any other assignment from the legacy platform answers 409 legacy_managed until your move to v1 is done. Takes ?dry_run=true and Idempotency-Key.

Request
DELETE/v1/tag-assignments/{id}
curl -X DELETE https://api.aleta.ai/v1/tag-assignments/01a14e89-1050-7dea-9609-99a3b1fc77f3 \
  -H "Authorization: Bearer {access_token}"
  • Assets — the most common tagging target.
  • Limits — rules that can target classifications.