Report subscriptions
A report subscription renders a pack of your report definitions on a schedule and mails it to your users. Reads need reports:read and the reports module on read in one of your groups; writes need reports:write and an operator seat (owner, admin, advisor) or a group with the reports module on read_write. Every write takes ?dry_run=true and an Idempotency-Key header and is logged in the change history.
The pack is rendered with the access of the user who made the subscription, so only they, a firm admin or Aleta may change it; another operator gets 403. A subscription Aleta set up for you (owner: aleta) is closed to your people, admins included: changing or archiving it is a 403 with the text Aleta set this up for you: only Aleta can change it.
Data model
idstringStable identifier for the subscription. A UUID.
namestringThe subscription's name.
statusstringdraft,activeorpaused. Only an active subscription is sent; it needs a name, at least one entry, a recipient for every entry, a client (the subscription's, every entry's definition's, or every entry scoped to a client), no entry for an archived definition and, unlessmanual, a schedule that resolves. Otherwise settingactiveis a400that lists what is missing.ownerstringaleta(Aleta set it up for you) ortenant(your own).originstringv1. Subscriptions are made on the platform; the legacy platform's are not moved.client_idstring or nullThe client the subscription files its reports under.
created_by_user_idstringThe user who made the subscription; the pack is rendered with their access.
cadencestringmanual,daily,weekly,monthlyorquarterly.time_of_day, timezonestring or null, stringWhen it is sent (
HH:MM, 24h; null formanual) in an IANA time zone, e.g.Europe/Copenhagen.day_of_week, day_of_monthstring or null, integer or nullThe weekday (
mon…sun) of a weekly subscription and the day (1–31) of a monthly or quarterly one.business_days_onlybooleanSkip weekends: a daily subscription is not sent on Saturday or Sunday; any other send that falls on a weekend moves to the Monday.
entriesarray of objectThe pack, one line per report:
report_definition_id,format(pdf,xlsxorcsv),currency(ISO code or null),language(da,enor null),scope({level: lens, lens_id},{level: client, client_id}or null for the definition's own;{level: invalid}for a line saved outside v1 with a scope the sender does not know, which fails its run until the line is replaced) andrecipients(empty: the subscription's own).recipientsarray of objectWho receives the pack: your users, each
{user_id, email, name}.user_idis null on a stored address none of your users has.subjectstring or nullThe mail's subject. The mail body (
body) can be written but is not returned.next_run_at, last_run_attimestamp or nullThe next scheduled send and the last run. RFC 3339, UTC, with microseconds.
created_at, updated_attimestampRFC 3339, UTC, with microseconds.
archived_at, archived_by, archive_reasontimestamp, string, string or nullSet once DELETE archived the subscription. Null while it is live.
List report subscriptions
Returns the subscriptions you can see by id, as a cursor list. Archived subscriptions are left out unless asked for. An unknown query parameter is a 400.
Query parameters
client_idstringOnly this client's subscriptions.
statusstringdraft,activeorpaused.report_definition_idstringOnly subscriptions with an entry for this report definition.
include_archivedbooleanAlso archived subscriptions. Default
false.cursor, limitstring, integerThe page:
limitdefaults to 100, at most 1000.
curl https://api.aleta.ai/v1/report-subscriptions \
-H "Authorization: Bearer {access_token}"
{
"data": [
{
"id": "019f95f0-2d40-7b58-8f6e-9a3c1d7e5b02",
"name": "Monthly pack",
"status": "active",
"owner": "tenant",
"origin": "v1",
"client_id": "019dfeb0-0511-77a7-a8be-a911ab988a0a",
"created_by_user_id": "019dfe9f-77aa-7b10-8c2d-3e4f5a6b7c8d",
"cadence": "monthly",
"time_of_day": "07:00",
"timezone": "Europe/Copenhagen",
"day_of_week": null,
"day_of_month": 1,
"business_days_only": true,
"entries": [
{
"report_definition_id": "019f1a2b-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"format": "pdf",
"currency": "DKK",
"language": "da",
"scope": {
"level": "lens",
"lens_id": "019e0f1a-2b3c-7d4e-9f5a-6b7c8d9e0f1a"
},
"recipients": []
}
],
"recipients": [
{
"user_id": "019dfea0-1122-7344-8556-6778899aabbc",
"email": "cfo@client.example",
"name": "Client CFO"
}
],
"subject": "Your monthly report",
"next_run_at": "2026-11-02T06:00:00.000000Z",
"last_run_at": null,
"created_at": "2026-10-17T06:12:00.481213Z",
"updated_at": "2026-10-17T06:12:00.481213Z",
"archived_at": null,
"archived_by": null,
"archive_reason": null
}
],
"next_cursor": null,
"limit": 100
}
Retrieve a report subscription
Returns one subscription, an archived one too. An unknown id, one you cannot see, or one that is not a UUID is a 404.
curl https://api.aleta.ai/v1/report-subscriptions/019f95f0-2d40-7b58-8f6e-9a3c1d7e5b02 \
-H "Authorization: Bearer {access_token}"
Create a report subscription
Creates a subscription and returns 201 with it, origin: v1 and owner: tenant (aleta when Aleta made it). An entry names one of your own report definitions: copy one of Aleta's first with POST /v1/report-definitions and copy_from. An archived definition, csv for a definition without exactly one data table, an unknown client or lens, or an incomplete schedule is a 400.
Body
name, cadence, timezonestringRequiredAs in the data model.
statusstringdraft(default),activeorpaused.client_id, time_of_day, day_of_week, day_of_month, business_days_onlyas in the data modelmanualtakes notime_of_day;dailyneeds it;weeklyalsoday_of_week;monthlyandquarterlyalsoday_of_month.entriesarray of objectEach
{report_definition_id, format?, currency?, language?, lens_id? | client_id?, recipients?}.formatdefaults topdf; an entry with bothlens_idandclient_idis a400.recipientsarray of objectEach
{email, name?, user_id?}, at most 200 per list. A recipient must be one of your users: a user with access to your firm, not deleted. An address none of your users has, or auser_idwhose address is not the one given, is a400. Each recipient must also see what they are sent, under their own access: the lens or client of every line mailed to them (a line without a scope is for its definition's lens, or else the subscription's or the definition's client); otherwise the write is a400naming the recipient. The user who made the subscription must see every line too, since the pack is rendered with their access; a change by an admin to another user's subscription is checked against that user.subject, bodystringThe mail's subject and body.
curl -X POST https://api.aleta.ai/v1/report-subscriptions \
-H "Authorization: Bearer {access_token}" \
-H "Idempotency-Key: {uuid}" \
-H "Content-Type: application/json" \
-d '{
"name": "Monthly pack",
"status": "active",
"client_id": "019dfeb0-0511-77a7-a8be-a911ab988a0a",
"cadence": "monthly",
"time_of_day": "07:00",
"timezone": "Europe/Copenhagen",
"day_of_month": 1,
"entries": [{"report_definition_id": "019f1a2b-3c4d-7e5f-8a9b-0c1d2e3f4a5b", "format": "pdf"}],
"recipients": [{"email": "cfo@client.example"}]
}'
Update a report subscription
Changes the fields you send; a field left out keeps its value, and null clears client_id, time_of_day, day_of_week or day_of_month. Returns 200 with the subscription. status: active brings an archived subscription back; any other change to an archived one is a 409 in_use whose next_action is this route with status.
curl -X PATCH https://api.aleta.ai/v1/report-subscriptions/019f95f0-2d40-7b58-8f6e-9a3c1d7e5b02 \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{"status": "paused"}'
Archive a report subscription
Archives the subscription: it is paused, never sent again and left out of the list; its deliveries are kept. Returns 200 with the archived subscription; ?reason= is kept as archive_reason. Any query parameter other than reason and dry_run is a 400. Archiving one already archived changes nothing. PATCH with status: active brings it back.
curl -X DELETE "https://api.aleta.ai/v1/report-subscriptions/019f95f0-2d40-7b58-8f6e-9a3c1d7e5b02?reason=replaced" \
-H "Authorization: Bearer {access_token}"