View as Markdown

Reports

A report is one file Aleta produced: a report the legacy customer portal generated (source: "customer_portal"), a report the legacy blob service holds (source: "legacy_blob"), a file a report subscription rendered (source: "report_subscription"), or a file you asked for with Create a report (source: "report_run"). Reading requires the reports:read scope and the reports module at read. You see the reports of the clients you see; a report for a lens also needs that lens to be one you see.

The report object

idstring

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

sourcestring

customer_portal, legacy_blob, report_subscription or report_run.

originstring

legacy (made on the legacy platform: customer_portal and legacy_blob) or v1.

namestring

The report's name: the legacy portal's English name, or the rendered file's name.

name_keystring or null

The legacy localisation key (report_name.*). Legacy reports only.

client_idstring or null

The client the report is filed under.

lens_idstring or null

The lens the report is for, when it has one. A rendered file is for its subscription line's lens, or else its report definition's lens.

report_definition_idstring or null

The report definition a subscription rendered.

legacy_idstring or null

The id the legacy portal showed, as a decimal string. Customer-portal reports only.

report_subscription_idstring or null

The subscription that rendered the file.

job_idstring or null

The job that rendered a report_run.

as_of_datestring or null

The reporting date, YYYY-MM-DD. null for a subscription render stored before renders recorded it.

periodstring or null

daily, monthly, quarterly, half_yearly or yearly.

groupstring or null

daily, risk, performance, controlling, esg or accounting.

formatstring

pdf, xlsx, csv or other.

created_atstring

When the file was made, ISO 8601 in UTC.


GET/v1/reports

List reports

Returns reports newest first (created_at, then id) in the standard v1 list envelope. A legacy blob report is listed in its newest version only, as the legacy portal listed it. An unknown source, to_date before from_date, or any parameter not listed here is a 400.

Query parameters

client_idstring

Only this client's reports.

lens_idstring

Only this lens's reports.

sourcestring

customer_portal, legacy_blob, report_subscription or report_run.

legacy_idstring

Only the customer-portal report with this legacy id.

from_datestring

Reporting date on or after this day, YYYY-MM-DD. A report without a reporting date is left out by a date filter.

to_datestring

Reporting date on or before this day.

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/reports
curl -G https://api.aleta.ai/v1/reports \
  -H "Authorization: Bearer {access_token}" \
  -d source=customer_portal
Response
{
  "data": [
    {
      "id": "0190f5f1-9f8e-7d6c-8b5a-493827161504",
      "source": "customer_portal",
      "origin": "legacy",
      "name": "Monthly report",
      "name_key": "report_name.m10a",
      "client_id": "0190f5e0-1111-7aaa-8bbb-0123456789ab",
      "lens_id": "0190f5e0-2222-7aaa-8bbb-0123456789ab",
      "report_definition_id": null,
      "legacy_id": "48211",
      "report_subscription_id": null,
      "job_id": null,
      "as_of_date": "2026-06-30",
      "period": "monthly",
      "group": "performance",
      "format": "pdf",
      "created_at": "2026-07-01T06:00:00.104000Z"
    }
  ],
  "next_cursor": null,
  "limit": 100
}

GET/v1/reports/{id}

Get a report

Returns one report. A report you do not see, or an id that is not a UUID, is a 404.

Request
GET/v1/reports/{id}
curl https://api.aleta.ai/v1/reports/0190f5f1-9f8e-7d6c-8b5a-493827161504 \
  -H "Authorization: Bearer {access_token}"

GET/v1/reports/{id}/download

Download a report

Returns the report's file: 200 with the bytes, the file's Content-Type, Content-Length when the storage reports it, Content-Disposition with the file's name, and Cache-Control: no-store, private. Requires reports:read; the same rules as Get a report decide whether you may read it. No storage URL is ever returned. Every download is recorded in your audit trail.

Query parameters

dispositionstring

attachment (the default: save the file) or inline (show it in the browser). Any other value, or any other parameter, is a 400.

The file is served from Aleta's storage in your tenant's residency. A legacy report whose file has not been moved to Aleta's storage, and a file missing from Aleta's storage, are a 404. A file in Aleta's storage larger than 32 MiB is a 422 with code file_too_large. While the storage is not configured the route answers 503.

Request
GET/v1/reports/{id}/download
curl -OJ https://api.aleta.ai/v1/reports/0190f5f1-9f8e-7d6c-8b5a-493827161504/download \
  -H "Authorization: Bearer {access_token}"

POST/v1/reports

Create a report

Renders one of your report definitions (/v1/report-definitions) once, for a lens or a client, as of a day, and answers 202 Accepted with a job and Location: /v1/jobs/{job_id} (also on a replay, not on a dry run). Follow it with GET /v1/jobs/{job_id} (needs platform:read); when it has succeeded, the file is in the list with source: "report_run" and this job_id, and can be downloaded. Nothing is mailed. Requires reports:write and the reports module at read_write. Takes ?dry_run=true and Idempotency-Key like every v1 write.

You also need a grant on the whole client of the scope: on the tenant, on the client (a read-only client grant counts), or as the client's advisor. For a lens, that is the lens's client. A grant on one entity or account, or a shared lens, is not enough: the answer is 403, because the report shows the whole client.

Body

report_definition_idstring

Required. One of your own definitions; copy an Aleta definition with copy_from first. It must not be archived.

lens_idstring

The lens to report on. Send exactly one of lens_id and client_id; when the definition has a client, the lens or client must belong to it.

client_idstring

The client to report on.

formatstring

Required. pdf or csv; csv needs a definition with exactly one bound data table. xlsx is not offered.

as_of_datestring

The reporting date, YYYY-MM-DD. Defaults to, and may not be after, the day the scope's data is released through (data_ready_through in GET /v1/data-status). The definition's period (for example the last full month) resolves as a scheduled delivery for that date would; a definition created with POST /v1/report-definitions covers the year to date.

currencystring

An ISO 4217 code; the definition's currency when absent.

languagestring

da or en. Only a definition with translations changes language; its authored text stays as written otherwise.

Every refusal is a 400 with the reason: an unknown field, a format, language, currency or as_of_date not as described, both or neither scope, a scope you do not see, an unknown or archived definition, a scope outside the definition's client, csv on a definition that cannot render it, a date after the released day, or a scope with no released data yet. The rendering reads no commentary, so a run records none. A caller without a grant on the whole client gets 403 (see above).

Request
POST/v1/reports
curl -X POST https://api.aleta.ai/v1/reports \
  -H "Authorization: Bearer {access_token}" \
  -H "Idempotency-Key: q3-pack-lens-a" \
  -H "Content-Type: application/json" \
  -d '{"report_definition_id": "0190f5e0-4444-7aaa-8bbb-0123456789ab", "lens_id": "0190f5e0-2222-7aaa-8bbb-0123456789ab", "format": "pdf", "as_of_date": "2026-09-30"}'
Response
{
  "job_id": "0190f5f3-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
  "status": "queued",
  "report_definition_id": "0190f5e0-4444-7aaa-8bbb-0123456789ab",
  "lens_id": "0190f5e0-2222-7aaa-8bbb-0123456789ab",
  "client_id": "0190f5e0-1111-7aaa-8bbb-0123456789ab",
  "format": "pdf",
  "as_of_date": "2026-09-30",
  "currency": null,
  "language": null,
  "created_at": "2026-10-18T09:00:00.123456Z"
}