Calculation runs
A calculation run recalculates holdings and returns for one scope from a day you choose to yesterday. Aleta recalculates by itself whenever data changes; a run is for when you want a scope recalculated now. The run writes staged figures, not the published ones you read; releasing staged figures is described under publish runs. Reading requires the platform:read scope and the operations module at read; starting a run requires platform:write, operations at read_write, and a grant on every cash and custody account the run recalculates. An admin sees every run; another user sees the runs they started.
Only a tenant that has moved to the platform recalculates here. Before the move, starting a run answers 409 legacy_managed.
The calculation run object
idstringStable identifier for the run. A UUID — treat it as opaque.
statusstringpending(stored, not started yet),running,succeededorfailed. A run that has not started within an hour isfailedwithnot_started. A run with any failed calculation isfailed, also when the rest succeeded.scopeobjectkind(cash_account,custody_account,asset,entityorclient) andid.custody_account_idstring or nullFor an asset: the custody account it is recalculated in.
nullmeans every custody account holding it.from_datestringThe first day recalculated,
YYYY-MM-DD.to_datestringThe last day: the day before the run was asked for (UTC).
requested_by_user_idstring or nullWho asked for the run.
created_atstringWhen the run was asked for, ISO 8601 in UTC with microseconds.
finished_atstring or nullWhen the run ended: its last calculation, or when it was refused or gave up waiting.
nullwhile it ispendingorrunning.progressobjecttotal(the calculations the run is made of;0until it started, and when the scope had nothing to recalculate),succeededandfailed(calculations that failed or that the platform cannot run yet).failed_countintegerEvery failure, also those past the 10 in
failures.failuresarrayAt most 10, each
{ "message": … }: a calculation's error (newest first), a calculation the platform cannot run yet (the platform cannot run this calculation yet: …), or why the run did not start, such asempty_scope,not_foundornot_started. A message longer than 500 characters is cut there and ends in....
A run is kept for 30 days; an older one is no longer listed and is a 404.
Start a run
Stores the run as pending and answers 202 Accepted with it and Location: /v1/calculation-runs/{id} (also on a replay, not on a dry run); the platform starts it within minutes. Takes ?dry_run=true and Idempotency-Key like every v1 write.
Body
scopeobjectRequired.
kind(cash_account,custody_account,asset,entityorclient) andid(a UUID). Any other kind is a400.custody_account_idstring or nullOptional, and only with an asset: recalculate it in this custody account only. Sent with another kind, it is a
400.from_datestringRequired. The first day,
YYYY-MM-DD, on or before yesterday.
A field the body does not take, in the body or in scope, is a 400.
Refusals, in this order: 400 bad_request for the body (also a from_date that is not YYYY-MM-DD or is after yesterday), 404 not_found for a scope or custody_account_id you do not see, 403 forbidden for a scope with a cash or custody account your grants do not cover (for an asset: the custody account you name, or else every cash and custody account it is booked on), 409 legacy_managed before your tenant has moved. The 403 and 409 come also on a dry run and before a replay.
curl -X POST https://api.aleta.ai/v1/calculation-runs \
-H "Authorization: Bearer {access_token}" \
-H "Idempotency-Key: 6c1f7d0e" \
-H "Content-Type: application/json" \
-d '{"scope": {"kind": "cash_account", "id": "6b1d2f0a-3c4e-4f5a-8b7c-9d0e1f2a3b4c"}, "from_date": "2026-10-01"}'
{
"id": "0190f5f2-1b2c-7d3e-8f40-5a6b7c8d9e10",
"status": "pending",
"scope": { "kind": "cash_account", "id": "6b1d2f0a-3c4e-4f5a-8b7c-9d0e1f2a3b4c" },
"custody_account_id": null,
"from_date": "2026-10-01",
"to_date": "2026-10-17",
"requested_by_user_id": "0190f5e0-3333-7aaa-8bbb-0123456789ab",
"created_at": "2026-10-18T09:00:00.000000Z",
"finished_at": null,
"progress": { "total": 0, "succeeded": 0, "failed": 0 },
"failed_count": 0,
"failures": []
}
List runs
Returns runs newest first (created_at, then id) in the standard v1 list envelope: data, next_cursor (null on the last page) and limit. Runs older than 30 days are not listed.
Query parameters
limitintegerPage size. Defaults to 100, capped at 1 000.
cursorstringThe
next_cursorof the previous page. A cursor that cannot be read is a400.
An unknown query parameter is a 400.
curl https://api.aleta.ai/v1/calculation-runs \
-H "Authorization: Bearer {access_token}"
{
"data": [
{
"id": "0190f5f2-1b2c-7d3e-8f40-5a6b7c8d9e10",
"status": "succeeded",
"scope": { "kind": "cash_account", "id": "6b1d2f0a-3c4e-4f5a-8b7c-9d0e1f2a3b4c" },
"custody_account_id": null,
"from_date": "2026-10-01",
"to_date": "2026-10-17",
"requested_by_user_id": "0190f5e0-3333-7aaa-8bbb-0123456789ab",
"created_at": "2026-10-18T09:00:00.000000Z",
"finished_at": "2026-10-18T09:04:12.318204Z",
"progress": { "total": 34, "succeeded": 34, "failed": 0 },
"failed_count": 0,
"failures": []
}
],
"next_cursor": null,
"limit": 100
}
Get a run
Returns one run. A run you do not see, older than 30 days, or an id that is not a UUID is a 404.
curl https://api.aleta.ai/v1/calculation-runs/0190f5f2-1b2c-7d3e-8f40-5a6b7c8d9e10 \
-H "Authorization: Bearer {access_token}"