View as Markdown

Tenants

These routes are Aleta's fleet view of the tenants it runs. Only Aleta's fleet key calls them: a key made in internal.aleta.io, bound to one tenant and to the Aleta staff member who made it, which acts in that tenant as Aleta. A customer's admin, and a person's own login, get 403 forbidden; a customer reads its own tenant with GET /v1/tenants/current. Only Aleta closes a tenant. That call comes from internal.aleta.io and is named after the Aleta person who approved it. No MCP tool reaches it. Nothing is deleted: the tenant, its data and its audit trail stay and can be found again. From the closing day every login, API key and feed of the tenant stops.

The tenant model

idstring

The tenant id.

namestring

The tenant's name.

regionstring

The region the tenant's data lives in, for example aws-eu-central-1.

statusstring

active, provisioning, migrating, suspended or closed.

closed_ondate or null

The first day the tenant is closed, YYYY-MM-DD, also while that day is still to come; null when no closure is open.

planstring or null

free, starter, professional, enterprise or custom.

agreement_started_attimestamp or null

When the tenant's agreement with Aleta started.

agreement_ends_attimestamp or null

When the agreement ends.

modulesarray of string

The modules a group of the tenant can hold (GET /v1/permissions). Every tenant has all fifteen.

flagsobject

What Aleta has sold the tenant: ai_enabled (true unless AI is switched off), cube_enabled, api_enabled and mcp_enabled.

white_label_levelstring

simple, standard or extended.

created_attimestamp

When the tenant was created.

updated_attimestamp

When the tenant was last changed.


GET/v1/tenants

List tenants

Every tenant Aleta runs, newest first, in the standard v1 list envelope (data, next_cursor, limit). Closed tenants are left out unless asked for with ?status=closed. The route needs the platform:read scope and the fleet key. It reads the catalog only and never opens a tenant's database. Any other query parameter is a 400 bad_request.

Query parameters

statusstring

Only tenants with this status, one of the model's five; any other value is a 400.

regionstring

Only tenants in this region.

cursorstring

The next_cursor of the previous page. A cursor that does not decode is a 400.

limitinteger

Page size, 1 to 1000. Defaults to 100.

Request
GET/v1/tenants
curl https://api.aleta.ai/v1/tenants?status=active \
  -H "Authorization: Bearer {fleet_access_token}"
Response
{
  "data": [
    {
      "id": "3f600564-957b-4aab-96ed-fd0118cfd805",
      "name": "Example Family Office",
      "region": "aws-eu-central-1",
      "status": "active",
      "closed_on": null,
      "plan": "enterprise",
      "agreement_started_at": null,
      "agreement_ends_at": null,
      "modules": ["core", "market_data", "transactions", "registrations", "limits", "benchmarks", "risk", "private_markets", "documents", "reports", "operations", "audit", "esg", "wealth_map", "allocation"],
      "flags": { "ai_enabled": true, "cube_enabled": false, "api_enabled": true, "mcp_enabled": false },
      "white_label_level": "simple",
      "created_at": "2026-04-02T09:12:44.103201Z",
      "updated_at": "2026-10-18T10:01:02.000000Z"
    }
  ],
  "next_cursor": null,
  "limit": 100
}

GET/v1/tenants/{tenant_id}

Retrieve a tenant

One tenant, whatever its status. The fleet key reads every tenant, not only its own; only writes are kept to the key's own tenant. The route needs the platform:read scope and the fleet key. An id that is no uuid is 400 bad_request, an unknown one 404 not_found; anyone but the fleet key gets 403 forbidden first.

Request
GET/v1/tenants/{tenant_id}
curl https://api.aleta.ai/v1/tenants/3f600564-957b-4aab-96ed-fd0118cfd805 \
  -H "Authorization: Bearer {fleet_access_token}"

PATCH/v1/tenants/{tenant_id}

Update a tenant

Changes the fleet key's own tenant; another tenant is 404 not_found, and an id that is no uuid 400 bad_request. Every field is optional and only the fields sent change. The answer is 200 with the tenant. The route needs the platform:write scope and the fleet key of an Aleta operator: a key of Aleta's support staff reads only (403 forbidden). ?dry_run=true and Idempotency-Key work as on every v1 write. Unknown fields are 400 bad_request. Each change stands in the tenant's own change log (GET /v1/audit-events, resource tenant) with the Aleta staff member, the fleet key and the tenant before and after.

status active reopens the tenant: a closure whose day is still to come is cancelled, the tenant stays open, closed_on becomes null, and the custodian authorities the closure sent to revoke-in-progress get their status back. It goes alone, with an optional reason; anything else with it, or another status, is 400. A tenant with no open closure answers unchanged. A tenant already closed is reopened in internal.aleta.io, as its fleet key stops with it.

A region change runs as a tenant move. It needs confirmed_by (the Aleta person who approved it) and reason, or the answer is 400; it needs a staff owner or admin behind the key, or the answer is 403. v1 does not start tenant moves yet, so a region change is answered 409 conflict and is started in internal.aleta.io. A body with region takes this path whatever else it holds, status included, and changes nothing. MCP never sends region.

Body parameters

statusstring

active: reopen the tenant. See above.

namestring

1 to 128 characters.

planstring or null

free, starter, professional, enterprise or custom; null clears it.

flagsobject

Any of ai_enabled, cube_enabled, api_enabled and mcp_enabled, each true or false.

white_label_levelstring

simple (Aleta's apps with the tenant's branding), standard (also the tenant's own apps) or extended (also its own colours and domain).

regionstring

The region to move the tenant's data to. See above.

confirmed_bystring

With region: the Aleta person who approved the move.

reasonstring

With region: why the tenant moves. With status: why it reopens.

Request
PATCH/v1/tenants/{tenant_id}
curl -X PATCH https://api.aleta.ai/v1/tenants/3f600564-957b-4aab-96ed-fd0118cfd805 \
  -H "Authorization: Bearer {fleet_access_token}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: {idempotency_key}" \
  -d '{ "plan": "enterprise", "flags": { "cube_enabled": true }, "white_label_level": "standard" }'

DELETE/v1/tenants/{tenant_id}

Close a tenant

Closes the tenant from closed_on. When that day has come (in Copenhagen), the tenant is closed at once and the answer has status closed. A later day is recorded, the tenant stays open until then, and an hourly job closes it in the first hour of that day. Sending it again with the same closed_on answers 200 and writes nothing. To close on another day, the tenant is first reopened (PATCH with status active).

Its custodian authorities go to revoke-in-progress when the closure is made: Aleta ends them at the bank once a person there confirms. The tenant's data is kept.

The route needs the platform:write scope and the fleet key of an Aleta operator; anyone else, Aleta's support staff included, gets 403 forbidden, and another tenant than the key's, or an id that is no uuid, is 404 not_found. Without a reason (or one over 1000 characters), or without confirmed_by naming an active Aleta staff member, the answer is 400 with code reason_required or confirmation_required. A tenant that still runs on the legacy platform is 409 legacy_managed; a tenant in a running move (as source or destination) is 409 in_use; a tenant that already closes on another day, is closed already, or is not yet built (provisioning) is 409 conflict.

The closure is kept in the tenant's events with the date, the reason, the approving person and the key that sent it, and in the tenant's change list. ?dry_run=true and Idempotency-Key work as on every v1 write.

Body parameters

closed_ondate

The first day the tenant is closed, YYYY-MM-DD. Today in Copenhagen when left out.

reasonstring

Why the tenant closes, at most 1000 characters. Required.

confirmed_bystring

The user id of the Aleta person who approved the closure in internal.aleta.io. Required.

The answer is the tenant, as Retrieve a tenant shows it: status closed once closed_on has come, until then the tenant's status (usually active), and closed_on set.

Request
DELETE/v1/tenants/{tenant_id}
curl -X DELETE https://api.aleta.ai/v1/tenants/3f600564-957b-4aab-96ed-fd0118cfd805 \
  -H "Authorization: Bearer {fleet_access_token}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: {idempotency_key}" \
  -d '{
    "closed_on": "2026-10-17",
    "reason": "Contract ended.",
    "confirmed_by": "019f8d08-a5fe-70d9-a454-e753f24658f4"
  }'
Response
{
  "id": "3f600564-957b-4aab-96ed-fd0118cfd805",
  "name": "Example Family Office",
  "region": "aws-eu-central-1",
  "status": "closed",
  "closed_on": "2026-10-17",
  "plan": "enterprise",
  "agreement_started_at": "2024-01-01T00:00:00.000000Z",
  "agreement_ends_at": null,
  "modules": ["core", "market_data", "transactions", "registrations", "limits", "benchmarks", "risk", "private_markets", "documents", "reports", "operations", "audit", "esg", "wealth_map", "allocation"],
  "flags": { "ai_enabled": true, "cube_enabled": false, "api_enabled": true, "mcp_enabled": false },
  "white_label_level": "simple",
  "created_at": "2024-01-01T00:00:00.000000Z",
  "updated_at": "2026-10-17T07:12:40.118000Z"
}
  • Data deletion: erasure of a person's data, which a closure does not do.