ReferenceReference by module

Reports API

Every Reports action (5) and data model (2): endpoints, scopes, input, preconditions, events and examples.

Sales and money reports, and who is allowed to see each one.

Module code reports · 5 actions · 2 data models · 4 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: reports (everything), reports:read (read only) or reports:<capability>.

Resources

ResourceTableList and readPOSTPATCHDELETE
report_exportsreport_export/api/v1/report_exports
report_schedulesreport_schedule/api/v1/report_schedules

Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.

Actions

ActionNeedsWhat it does
reports.create_schedulereports:manageSchedule a report by email
reports.delete_schedulereports:manageStop a scheduled report
reports.record_exportreports:exportRecord a report export
reports.request_exportreports:exportExport every row
reports.send_digestreports:manageSend a scheduled report

reports.create_schedule

Schedule a report by email — Sends a report’s headline numbers through a notification rule on a fixed calendar.

Needs reports:manage · changes data

POSThttps://app.getera.io/api/v1/report_schedules/actions/create_schedule
API key or OAuth token · reports:manage
  • Canonical address: POST /api/v1/actions/reports.create_schedule

Input

FieldTypeRequiredNotes
report_keystringyesReport · max 64
rule_iduuidyesDeliver through · id of notification_rule
frequencystring (enum)yesHow often · Allowed values: daily, weekly, monthly
send_hournumberHour · Local time in the workspace timezone. · min 0 · max 23
weekdaynumberWeekday · 0 = Sunday. Only used for weekly. · min 0 · max 6
window_monthsnumberMonths covered · min 1 · max 24

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
unknown_reportThe report must exist in the registry.
rule_not_foundThe notification rule must exist in this workspace.
rule_not_for_digestsThe rule must cover the reports.digest event.
schedule_existsThe same report is not scheduled twice through one rule at the same frequency.

Events it publishes: reports.schedule_created

What it writes: report_schedule (insert) — The schedule, with its first send time

curl -X POST https://app.getera.io/api/v1/report_schedules/actions/create_schedule \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"report_key":"Report","rule_id":"NOTIFICATION_RULE_ID","frequency":"daily"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "reports.schedule_created"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.reportSchedules.createSchedule({
  report_key: "Report",
  rule_id: "NOTIFICATION_RULE_ID",
  frequency: "daily"
})
era report_schedules create_schedule \
  --report-key "Report" \
  --rule-id "NOTIFICATION_RULE_ID" \
  --frequency "daily"
tools/call
{
  "name": "era__reports__create_schedule",
  "arguments": {
    "report_key": "Report",
    "rule_id": "NOTIFICATION_RULE_ID",
    "frequency": "daily"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold reports:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 unknown_report, rule_not_found, rule_not_for_digests, schedule_exists · 429 slow down

reports.delete_schedule

Stop a scheduled report — Removes the schedule. Digests already sent stay in the notification history.

Needs reports:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/report_schedules/{id}/actions/delete_schedule
API key or OAuth token · reports:manage
  • Canonical address: POST /api/v1/actions/reports.delete_schedule

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Schedule · id of report_schedule

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
schedule_not_foundThe schedule must exist in this workspace.

Events it publishes: reports.schedule_deleted

What it writes: report_schedule (delete) — The schedule row

curl -X POST https://app.getera.io/api/v1/report_schedules/REPORT_SCHEDULE_ID/actions/delete_schedule \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "reports.schedule_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.reportSchedules.deleteSchedule("REPORT_SCHEDULE_ID")
era report_schedules delete_schedule REPORT_SCHEDULE_ID
tools/call
{
  "name": "era__reports__delete_schedule",
  "arguments": {
    "id": "REPORT_SCHEDULE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold reports:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 schedule_not_found · 429 slow down

reports.record_export

Record a report export — Adds a row to the export history when somebody downloads a report as CSV.

Needs reports:export · reaches outside (sends, publishes or charges)

POSThttps://app.getera.io/api/v1/report_exports/actions/record_export
API key or OAuth token · reports:export
  • Canonical address: POST /api/v1/actions/reports.record_export

Input

FieldTypeRequiredNotes
report_keystringyesReport · max 64
window_monthsnumberWindow (months) · min 1 · max 24
comparestringCompared with · max 16
row_countnumberyesRows · min 0 · max 10000000
filenamestringFile name · max 200

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
unknown_reportThe report must exist in the registry.

Events it publishes: reports.exported

What it writes: report_export (insert) — One history row per download

curl -X POST https://app.getera.io/api/v1/report_exports/actions/record_export \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"report_key":"Report","row_count":1}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "reports.exported"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.reportExports.recordExport({
  report_key: "Report",
  row_count: 1
})
era report_exports record_export \
  --report-key "Report" \
  --row-count 1
tools/call
{
  "name": "era__reports__record_export",
  "arguments": {
    "report_key": "Report",
    "row_count": 1
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold reports:export · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 unknown_report · 429 slow down

reports.request_export

Export every row — Queues a CSV of every row a report reaches in a period; it is ready to download a moment later.

Needs reports:export · reaches outside (sends, publishes or charges)

POSThttps://app.getera.io/api/v1/report_exports/actions/request_export
API key or OAuth token · reports:export
  • Canonical address: POST /api/v1/actions/reports.request_export

Input

FieldTypeRequiredNotes
datasetKeystringyesReport · max 120
filtersobject / arrayFilters
fromdate-timeyesFrom
todate-timeyesTo
timezonestringTime zone · max 64

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
dataset_not_foundThe report must exist and you must be able to open its module.
invalid_report_configFilters must name the report’s own fields, and the period must run forwards.

Events it publishes: reports.exported

What it writes: report_export (insert) — The request, queued; the worker fills in the file

curl -X POST https://app.getera.io/api/v1/report_exports/actions/request_export \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"datasetKey":"Report","from":"2026-11-02T09:00:00Z","to":"2026-11-02T09:00:00Z"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "reports.exported"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.reportExports.requestExport({
  datasetKey: "Report",
  from: "2026-11-02T09:00:00Z",
  to: "2026-11-02T09:00:00Z"
})
era report_exports request_export \
  --dataset-key "Report" \
  --from "2026-11-02T09:00:00Z" \
  --to "2026-11-02T09:00:00Z"
tools/call
{
  "name": "era__reports__request_export",
  "arguments": {
    "datasetKey": "Report",
    "from": "2026-11-02T09:00:00Z",
    "to": "2026-11-02T09:00:00Z"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold reports:export · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 dataset_not_found, invalid_report_config · 429 slow down

reports.send_digest

Send a scheduled report — Machine-only: the report scheduler runs it when a schedule is due.

Needs reports:manage · reaches outside (sends, publishes or charges)

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/report_schedules/{id}/actions/send_digest
API key or OAuth token · reports:manage
  • Canonical address: POST /api/v1/actions/reports.send_digest

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Schedule · id of report_schedule

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
schedule_not_foundThe schedule must exist and be active.

Events it publishes: reports.digest

What it writes: report_schedule (update) — Stamps the send and moves the next run on

Errors: 401 no or expired credential · 403 the credential does not hold reports:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 schedule_not_found · 429 slow down

Data models

ReportExport

Table report_export · Resource report_exports

  • GET /api/v1/report_exports
  • GET /api/v1/report_exports/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
report_keystring · text
formatstring · text
window_monthsinteger · int4yes
comparestring · textyes
row_countinteger · int4
filenamestring · textyes
exported_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
dataset_keystring · textyes
queryobject · jsonbyes
period_fromstring (date-time) · timestamptzyes
period_tostring (date-time) · timestamptzyes
timezonestring · textyes
statusstring · textqueued, running, done, failed
contentstring · textyes
errorstring · textyes
finished_atstring (date-time) · timestamptzyes

Primary key: id

Checks:

  • CHECK ((format = 'csv'::text))
  • CHECK ((row_count >= 0))

ReportSchedule

Table report_schedule · Resource report_schedules

  • GET /api/v1/report_schedules
  • GET /api/v1/report_schedules/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
report_keystring · text
rule_idstring (uuid) · uuidnotification_rule
frequencystring · textdaily, weekly, monthly
send_hourinteger · int4
weekdayinteger · int4
window_monthsinteger · int4
activeboolean · bool
next_run_atstring (date-time) · timestamptz
last_sent_atstring (date-time) · timestamptzyes
created_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK (((send_hour >= 0) AND (send_hour <= 23)))
  • CHECK (((weekday >= 0) AND (weekday <= 6)))
  • CHECK (((window_months >= 1) AND (window_months <= 24)))

Events

Workflows and webhooks react to these events.

EventWhat happensPayload
reports.digestA scheduled report digest is ready; delivered only to the rule it names.schedule_id, report_key, title, route, lines, notificationRuleId
reports.exportedA report was downloaded as CSV.export_id, report_key, row_count
reports.schedule_createdA report was scheduled for delivery.schedule_id, report_key, frequency
reports.schedule_deletedA scheduled report was stopped.schedule_id, report_key
Was this page helpful?